<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>perillaroc on 风中飞舞</title><link>https://blog.perillaroc.wang/authors/perillaroc/</link><description>Recent content in perillaroc on 风中飞舞</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="https://blog.perillaroc.wang/authors/perillaroc/index.xml" rel="self" type="application/rss+xml"/><item><title>视界：软件工程的未来两年</title><link>https://blog.perillaroc.wang/post/2026/04/2026-04-view-the-next-two-years-of-software-engineering/</link><pubDate>Mon, 06 Apr 2026 11:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2026/04/2026-04-view-the-next-two-years-of-software-engineering/</guid><description>&lt;p&gt;&lt;em&gt;努力成为整体思考、持续学习、并推动技术解决真实问题的工程师&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;本文翻译自 Addy Osmani 的一篇博客文章，从五个方面分析软件工程领域近期可能面临的发展趋势，并从初级开发者和高级开发者两个维度给出非常有价值建议。
译者本以为自己已经进阶成为一名高级开发者，读完这篇文章才发现原来一直以来扮演的都是初级开发者角色。
下面是译者总结的三个关键点，仅供参考。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;专注人类独有特质&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;未来无论怎么发展，程序员都不再只有编程。
要培养交流沟通能力，锻炼导师指导能力，精通领域知识，关注设计、安全和扩展性。
译者曾经认为做一个写代码的技术工作者就好了，但现实总是很难与理想保持同频，原来沟通技能之类的要求还是会落到每一个人头上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;做 T 型工程师&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在某个专业具有足够的深度，同时了解多个领域，成为精通某个专业领域的跨领域通才。
比如译者从事数值天气预报业务系统运维工作，熟悉系统的运行流程，但对数值天气预报模式程序本身缺乏足够的了解，应该在 AI 工具的加持下阅读模式源代码，加深对整个系统的全方位了解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;保持编程创造力&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过个人项目保持编程创造力，持续学习新工具和最佳实践。
译者近期完全没有个人项目，八小时之外的时间基本不会用来学习和编程，是时候开启新的个人项目了。&lt;/p&gt;
&lt;h2 id="原文信息"&gt;原文信息&lt;/h2&gt;
&lt;p&gt;The Next Two Years of Software Engineering&lt;/p&gt;
&lt;p&gt;by Addy Osmani, 2026.01.05&lt;/p&gt;
&lt;p&gt;&lt;a href="https://addyosmani.com/blog/next-two-years/"&gt;https://addyosmani.com/blog/next-two-years/&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下正文部分使用 Kimi 和 ChatGPT 翻译自原文，并根据译者理解有所修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;软件行业正处于一个奇特的拐点。
AI编码已经从&amp;quot;类固醇般的自动补全&amp;quot;演变为能够自主执行开发任务的智能体。
推动科技行业招聘热潮的经济繁荣已经让位于效率至上的要求：如今公司往往更看重盈利能力而非增长，偏好有经验的人才而非应届毕业生，青睐配备更好工具的精干小团队。&lt;/p&gt;
&lt;p&gt;与此同时，新一代开发者正以不同的考量进入职场：他们务实看待职业稳定性，对&amp;quot;奋斗文化&amp;quot;持怀疑态度，且从入行第一天起就习惯了 AI 辅助。&lt;/p&gt;
&lt;p&gt;接下来会发生什么确实充满不确定性。
以下是五个可能在 2026 年之前塑造软件工程发展的关键问题，并为每个问题提供两种对比的情景。
这些并非真正的预测，而是用于准备的视角。
目标是基于当前数据，并结合这个社区一贯具备的健康怀疑精神，制定一份清晰的路线图来应对未来。&lt;/p&gt;
&lt;h3 id="1-初级开发者问题"&gt;1. 初级开发者问题&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心要点&lt;/strong&gt;：初级开发者招聘可能因 AI 自动化入门级任务而崩溃，也可能因软件渗透到各行各业而反弹。两种未来都需要不同的生存策略。&lt;/p&gt;
&lt;p&gt;传统 &amp;ldquo;学编程→找初级工作→成长为高级工程师&amp;rdquo; 的路径正在动摇。
&lt;a href="https://www.finalroundai.com/blog/ai-is-making-it-harder-for-junior-developers-to-get-hired"&gt;哈佛一项针对 6200 万工作者的研究&lt;/a&gt;发现，当公司采用生成式 AI 时，初级开发者就业人数在六个季度内下降约 9-10%，而高级开发者岗位几乎不受影响。
过去三年，&lt;a href="https://restofworld.org/2025/engineering-graduates-ai-job-losses/"&gt;大型科技公司招聘的应届生减少了 50%&lt;/a&gt;。
正如&lt;a href="https://www.cio.com/article/4062024/demand-for-junior-developers-softens-as-ai-takes-over.html"&gt;一位工程师讽刺道&lt;/a&gt;：&amp;ldquo;当 AI 编码智能体成本更低时，为什么要花 9 万美元雇一个初级开发者？&amp;rdquo;&lt;/p&gt;</description></item><item><title>技术报告：软件工程的未来 - 研讨会结论与战略洞见</title><link>https://blog.perillaroc.wang/post/2026/03/2026-03-25-the-future-of-software-engineering/</link><pubDate>Mon, 30 Mar 2026 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2026/03/2026-03-25-the-future-of-software-engineering/</guid><description>&lt;h2 id="译者注"&gt;译者注&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;君以此始，必以此终&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;译者最近一个月才开始接触氛围编程，使用 Claude Opus 模型完善去年开发的一个试验项目 (mcv-workflow)，大受震撼，感觉大模型在 ecFlow 这类领域特定工具的编程能力上都已经碾压我了。&lt;/p&gt;
&lt;p&gt;由 thoughtworks 公司撰写的这篇研讨会总结报告正是对软件工程正在发生变革的一个写照。
没有人能说清未来会最终变成什么样，但所有人都认为未来一定不是现在这个样子。
推荐各位程序员朋友阅读。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The future of software engineering - Retreat findings and strategic insights&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原文链接： &lt;a href="https://www.thoughtworks.com/content/dam/thoughtworks/documents/report/tw_future%20_of_software_development_retreat_%20key_takeaways.pdf"&gt;https://www.thoughtworks.com/content/dam/thoughtworks/documents/report/tw_future%20_of_software_development_retreat_%20key_takeaways.pdf&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下正文内容使用 ChatGPT 和 Grok 翻译自原文，并根据译者理解有所修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;感谢各位参与本次研讨，共同探讨在 AI 重塑软件构建方式的背景下最关键的问题。
以下内容是对各分组讨论成果的综合提炼与总结。&lt;/p&gt;
&lt;p&gt;本次研讨遵循查塔姆宫守则 (Chatham House Rule)，因此本文不披露任何参与者姓名或机构信息。&lt;/p&gt;
&lt;p&gt;2026 年 2 月&lt;/p&gt;
&lt;h3 id="执行摘要"&gt;执行摘要&lt;/h3&gt;
&lt;p&gt;来自多家大型科技公司的资深工程实践者齐聚一堂，参加为期数日的研讨，直面 AI 正在改变软件开发所带来的核心问题。
讨论涵盖二十多个主题，但最重要的洞见并非来源于某一场单独的会议，而是出现在不同议题的交汇处。
我们发现，同样的关切在不同的人、不同的场景中反复出现。&lt;/p&gt;
&lt;p&gt;本报告提炼了这些跨领域的主题，并围绕当前管理者亟需理解与应对的模式进行组织。
本次研讨会并未形成一个统一的未来蓝图，但产出了更具价值的成果：一张“断层图”，标示出当前实践正在失效之处，以及新范式正在形成之地。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”我们在每个房间都反复问同一个问题：如果 AI 负责写代码，那工程到底去哪儿了？没有人给出相同的答案，但所有人都认同这个问题已经迫在眉睫。“&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="主题一览"&gt;主题一览&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;主题&lt;/th&gt;
					&lt;th&gt;时间范围&lt;/th&gt;
					&lt;th&gt;核心洞见&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;严谨性将走向何处？&lt;/td&gt;
					&lt;td&gt;当前&lt;/td&gt;
					&lt;td&gt;当 AI 编写代码时，工程质量不会消失，而是转移到规格说明、测试、约束与风险管理中&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;从代码审查到风险分级&lt;/td&gt;
					&lt;td&gt;当前&lt;/td&gt;
					&lt;td&gt;代码审查正在被拆解，其四大功能 (指导、一致性、正确性、信任) 都需要找到新归宿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;生产力/体验悖论&lt;/td&gt;
					&lt;td&gt;当前&lt;/td&gt;
					&lt;td&gt;开发者生产力与开发者体验正在脱钩，组织必须在两者之间做出权衡&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;安全被当成事后补救&lt;/td&gt;
					&lt;td&gt;当前&lt;/td&gt;
					&lt;td&gt;Agent 安全能力极度不足，仅授予邮箱访问权限就可能导致完整账户接管&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;中间循环 (Middle Loop)&lt;/td&gt;
					&lt;td&gt;当前 – 1年&lt;/td&gt;
					&lt;td&gt;在内循环编码与外循环交付之间，出现了一类新的“监督型工程工作”，尚未被正式命名&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;认知债务&lt;/td&gt;
					&lt;td&gt;当前 – 1年&lt;/td&gt;
					&lt;td&gt;技术债务 (technical debt) 正演变为认知债务 (cognitive debt)：系统复杂性与人类理解能力之间的差距&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent 拓扑&lt;/td&gt;
					&lt;td&gt;1–3年&lt;/td&gt;
					&lt;td&gt;康威定律同样适用于 Agent，企业架构需考虑其流动性 (mobility)、专业化 (specialization) 与漂移 (drift)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;知识图谱与语义层&lt;/td&gt;
					&lt;td&gt;1–3年&lt;/td&gt;
					&lt;td&gt;数十年的老技术突然重获新生，成为支持领域感知型 Agent 的基础层&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;角色的未来&lt;/td&gt;
					&lt;td&gt;1–3年&lt;/td&gt;
					&lt;td&gt;产品经理、开发者、设计师的角色正在融合；资深工程师要求提高，初级工程师反而更具价值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;自愈系统&lt;/td&gt;
					&lt;td&gt;2–5年&lt;/td&gt;
					&lt;td&gt;从人工事故响应转向 Agent 辅助自愈，首先必须解决“隐性知识 (latent knowledge)”问题&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;每个主题的详细发现如下。&lt;/p&gt;</description></item><item><title>2025年上半年工作总结</title><link>https://blog.perillaroc.wang/post/2025/08/2025-08-27-2025-h1-summary/</link><pubDate>Wed, 27 Aug 2025 15:39:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/08/2025-08-27-2025-h1-summary/</guid><description>&lt;p&gt;很久没有写工作阶段总结文章了，上一次还是《&lt;a href="https://blog.perillaroc.wang/post/2022/10/2022-10-08-2022-q3-summary/"&gt;2022年第三季度工作总结&lt;/a&gt;》，提到要以工作流工具为核心开展各项工作，两年时间过去了，我依然还要告诉自己要以工作流工具为核心工作。
过去的两年里，工作时间一半以上都在建设各种各样的 ecFlow 系统，比如 2023 年的 XXX 系统建设，2023 - 2024 年的业务系统迁移新超算，2024 - 2025 年的区域台风 V4.0 系统、下一代模式实时系统建设和多个省局区域模式系统，2025 年的冷备份系统建设。
而在工具软件开发方面 2024 年在绘图工具上投入了大量精力，反而完全搁置了工作流工具开发，有些舍本逐末了。
可见非常有必要进行阶段性总结，及时纠正错误的工作方向，确保自己朝着合理的目标前行。&lt;/p&gt;
&lt;p&gt;本文总结 2025 年上半年的个人工作，并对下半年作出展望。&lt;/p&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="系统运维"&gt;系统运维&lt;/h3&gt;
&lt;h4 id="运维分级"&gt;运维分级&lt;/h4&gt;
&lt;p&gt;为了进一步明确系统维护工作量，在室领导安排下，编写 NWP 业务系统运维分级方案，将系统分为核心系统、服务系统、试验系统、特殊服务系统和业务备份系统共 5 种类型，并设计了 P1 - P5 共 5 种维护级别，绘制实时系统运维分级图。
详情请浏览《&lt;a href="https://blog.perillaroc.wang/post/2025/03/2025-03-12-an-example-maintenance-level-for-nwp-systems-in-cemc-oper/"&gt;数值天气预报模式系统运维分级方案示例&lt;/a&gt;》。&lt;/p&gt;
&lt;h4 id="业务运行管理系统"&gt;业务运行管理系统&lt;/h4&gt;
&lt;p&gt;上半年也参与了单位和部门的软件集约统筹工作，总结了业务运行监控系统的现状、存在问题和发展计划。
详情请浏览《&lt;a href="https://blog.perillaroc.wang/post/2025/08/2025-08-27-thoughts-about-nwp-monitor-system/"&gt;数值天气预报业务系统监控平台设计思考&lt;/a&gt;》。
部分发展计划已融入到今年新增的某项工程项目中，笔者参与了该项工程项目的部分前期工作，但已和部门申请不再参与该工程项目的后续工作，不过笔者应该会继续开展业务系统建设和部署方面技术的研发工作，争取降低系统的部署难度，提高系统的可迁移性。&lt;/p&gt;
&lt;h4 id="冷备份系统建设"&gt;冷备份系统建设&lt;/h4&gt;
&lt;p&gt;部门用了2023到2024将近两年时间将 NWP 业务系统从 CMA-PI 迁移到 CMA-HPC2023-SC1，今年上半年部门将业务系统部署到 CMA-HPC2023-SC3，建立业务系统的冷备份系统，并在 CMA-HPC2023-SC1 重启期间完成切换演练。
笔者负责区域台风系统，全球、区域后处理系统的迁移部署，并协助部门组织同事共同撰写《2025冷备份系统演练方案》。&lt;/p&gt;
&lt;h4 id="一般工作"&gt;一般工作&lt;/h4&gt;
&lt;p&gt;在同事总结的业务系统产品表基础上，将其按照系统拆分，上传到内部文档共享库中，形成对外传输清单。&lt;/p&gt;
&lt;h3 id="业务系统建设"&gt;业务系统建设&lt;/h3&gt;
&lt;h4 id="全球模式"&gt;全球模式&lt;/h4&gt;
&lt;h5 id="wmc图片产品"&gt;WMC图片产品&lt;/h5&gt;
&lt;p&gt;更新全球绘图产品系统，为 WMC 网站新增图片产品，包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重新实现单要素图片并增加种类&lt;/li&gt;
&lt;li&gt;新增多要素绘图&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;新的绘图脚本使用 Python 实现，提供命令行接口。&lt;/p&gt;
&lt;p&gt;单要素图片使用更新后的 &lt;a href="https://github.com/cemc-oper/sokort"&gt;cemc-oper/sokort&lt;/a&gt; 工具调用 Python 绘图脚本。例如：&lt;/p&gt;</description></item><item><title>NWP业务系统监控平台设计思考</title><link>https://blog.perillaroc.wang/post/2025/08/2025-08-27-thoughts-about-nwp-monitor-system/</link><pubDate>Wed, 27 Aug 2025 15:13:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/08/2025-08-27-thoughts-about-nwp-monitor-system/</guid><description>&lt;p&gt;本文介绍笔者在今年上半年对 NWP 业务系统监控平台相关工作的一些思考，介绍当前现状，并给出一种未来发展的计划方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表笔者个人观点，文章中引用的相关材料仅用于探讨和交流，不能作为最终事实依据。
关于 NWP 业务系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。
如有任何疑问，建议查阅权威资料或咨询相关领域的专家。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="现状"&gt;现状&lt;/h2&gt;
&lt;p&gt;NWP 业务系统监控平台包括两个部分，下图给出了两个部分的示意图&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2025/devops/2025-08-nwp-monitor/nwp-monitor-current.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 NWP 业务系统监控平台现状&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="业务集成与控制"&gt;业务集成与控制&lt;/h3&gt;
&lt;p&gt;功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运行流程构建&lt;/li&gt;
&lt;li&gt;实时运行&lt;/li&gt;
&lt;li&gt;运行监控（ecFlow 界面）&lt;/li&gt;
&lt;li&gt;故障处理&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="业务运行监控"&gt;业务运行监控&lt;/h3&gt;
&lt;p&gt;功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运行监视（Web）&lt;/li&gt;
&lt;li&gt;故障告警（微信）&lt;/li&gt;
&lt;li&gt;运行信息展示&lt;/li&gt;
&lt;li&gt;运维管理（故障记录、更新记录、值班管理）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="存在问题"&gt;存在问题&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;研发到业务（R2O）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个系统单独建立 ecFlow 流程，系统之间缺乏代码/组件共享&lt;/li&gt;
&lt;li&gt;研发和业务运行流程不一致 (shell vs ecFlow)，显著增加业务部署成本&lt;/li&gt;
&lt;li&gt;系统建设在业务运行账户中直接进行，过于依赖开发人员的经验，缺少自动集成、自动部署功能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;业务到研发（O2R）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;监控网站仅面向运维需求开发，缺乏为模式研发人员提供业务运行信息&lt;/li&gt;
&lt;li&gt;故障分类过于简单，没有与系统更新相关联，缺少事务跟踪管理功能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;监控&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HPC 登录节点运行 ecFlow ，业务监控严重依赖超算，不方便同时监控多个超算上的业务系统&lt;/li&gt;
&lt;li&gt;网站前后端紧密耦合，依赖单一供应商的技术，存在供应链风险&lt;/li&gt;
&lt;li&gt;运行信息种类过少，需要在系统运行时生成更多运行信息，详细记录系统运行流程信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="计划"&gt;计划&lt;/h2&gt;
&lt;p&gt;下图展示了 NWP 业务系统监控平台未来发展的一种方案，形成 4 种相互关联的服务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;集成部署服务&lt;/li&gt;
&lt;li&gt;工作流调度服务&lt;/li&gt;
&lt;li&gt;运行监控服务&lt;/li&gt;
&lt;li&gt;事务追踪管理服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2025/devops/2025-08-nwp-monitor/nwp-monitor-plan.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 NWP 业务系统监控平台发展的一种方案&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;不同角度的功能特点&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;R2O&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;版本库 + 集成部署服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;O2R&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;版本库 + 事务追踪管理服务&lt;/li&gt;
&lt;li&gt;业务运行网站服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;监控&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>sokort项目停止维护</title><link>https://blog.perillaroc.wang/post/2025/07/2025-07-10-sokort-project-go-to-end/</link><pubDate>Wed, 27 Aug 2025 14:45:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/07/2025-07-10-sokort-project-go-to-end/</guid><description>&lt;p&gt;&lt;a href="https://github.com/cemc-oper/sokort"&gt;cemc-oper/sokort&lt;/a&gt; 项目封装 NWP 业务系统绘图脚本并提供新的调用接口。&lt;/p&gt;
&lt;p&gt;在近期工作中，笔者发现 sokort 项目存在一系列问题，计划停止 sokort 项目后续开发，仅进行简单维护。
笔者将择机推动 NWP 业务系统绘图脚本切换到 Python，并在业务更新时逐步使用绘图工具库原生接口代替 sokort 接口。&lt;/p&gt;
&lt;p&gt;本文简要介绍 sokort 项目的使用方法和应用情况，分析项目存在的问题，并尝试提供一种解决方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表笔者个人观点，文章中引用的相关材料仅用于探讨和交流，不能作为最终事实依据。
关于 NWP 业务系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。
如有任何疑问，建议查阅权威资料或咨询相关领域的专家。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;sokort 项目最早是为了解决业务系统 NCL 绘图脚本不容易使用的问题，将使用 NCL 绘图工具需要的生成绘图参数配置文件、设置环境变量、调用具体的绘图脚本等步骤隐藏到工具库内部，对外提供所有图片一致的命令行和 Python API 接口，应用在气象超算的实时业务系统和 CMADaaS 加工流水线上部署的绘图算法。&lt;/p&gt;
&lt;p&gt;命令行接口支持生成图片文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 -m sokort draw &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --config &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CONFIG_FILE_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --system grapes_gfs_gmf &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --plot-type cn.cape &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --start-time &lt;span style="color:#ae81ff"&gt;2025071000&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --forecast-time 000h &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --data-dir &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DATA_DIR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --work-dir .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Python 接口 &lt;code&gt;draw_plot&lt;/code&gt; 用于生成图片文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sokort &lt;span style="color:#f92672"&gt;import&lt;/span&gt; draw_plot 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;draw_plot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; system&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;cma_gfs_gmf&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;cn.t_2m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2025-07-09 00:00:00&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;144h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; verbose&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Python 接口 &lt;code&gt;show_plot&lt;/code&gt; 支持在 Jupyter Notebook 中显示图片&lt;/p&gt;</description></item><item><title>reki发布v2025.7.0版本</title><link>https://blog.perillaroc.wang/post/2025/07/2025-07-07-reki-v2025-7-release/</link><pubDate>Mon, 07 Jul 2025 21:18:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/07/2025-07-07-reki-v2025-7-release/</guid><description>&lt;p&gt;reki 项目已发布 &lt;a href="https://github.com/cemc-oper/reki/releases/tag/v2025.7.0"&gt;v2025.7.0&lt;/a&gt; 版本，可以使用 pip 安装或更新到最新版。&lt;/p&gt;
&lt;h2 id="新功能"&gt;新功能&lt;/h2&gt;
&lt;h3 id="使用cemc短要素名加载grib2要素场"&gt;使用CEMC短要素名加载GRIB2要素场&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;load_field_from_file&lt;/code&gt; 等函数从 GRIB2 文件中加载要素场时，函数参数 &lt;code&gt;parameter&lt;/code&gt;、&lt;code&gt;level_type&lt;/code&gt; 和 &lt;code&gt;level&lt;/code&gt; 分别被转换为字典形式的 GRIB 键值对，并合并到同一个字典对象中，随后使用该字典对象过滤 GRIB2 消息。
因此，检索某些要素场可以仅使用 CEMC 短要素名作为 parameter 参数。&lt;/p&gt;
&lt;p&gt;例如检索 2 米温度：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; reki.format.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;t2m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;注：reki 同样支持 ecCodes 的 shortName，比如使用 &lt;code&gt;parameter=&amp;quot;2t&amp;quot;&lt;/code&gt; 加载 2 米温度场。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;检索 0-3km 垂直风切变：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;shr(0-3000)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CEMC 短要素名包含在 &lt;code&gt;pandas.DataFrame&lt;/code&gt; 格式的 CEMC 要素清单 &lt;code&gt;CEMC_PARAM_TABLE&lt;/code&gt; 中，可以使用如下代码查看：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; reki.format.grib.config &lt;span style="color:#f92672"&gt;import&lt;/span&gt; CEMC_PARAM_TABLE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CEMC_PARAM_TABLE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;v2025.7.1：CEMC 短要素名支持 CMA-GFS GRIB2 数据。&lt;/p&gt;</description></item><item><title>从招聘信息看ECMWF对科学软件工程师的要求</title><link>https://blog.perillaroc.wang/post/2025/05/2025-05-20-ecmwf-job-of-nwp-operation/</link><pubDate>Sun, 06 Jul 2025 23:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/05/2025-05-20-ecmwf-job-of-nwp-operation/</guid><description>&lt;p&gt;ECMWF 发布了一条关于数值预报业务系统建设维护岗位的招聘信息，为 CAMS 系统招聘科学软件工程师，职级 A2，详细信息见如下网页：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jobs.ecmwf.int/Job/JobDetail?JobId=10316"&gt;Scientific Software Engineer - Atmospheric Composition Monitoring and Forecasting&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：因超过申请期限，该网页原文已无法访问。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从招聘信息看，该岗位与笔者当前从事岗位基本一致，侧重数值天气预报业务系统 (以下简称 NWP 业务系统) 建设及维护工作。
本文结合笔者当前岗位对该招聘信息中的核心职责和任职要求进行逐条对比，以期找到本岗位的发展趋势。&lt;/p&gt;
&lt;p&gt;下文使用 ECMWF 岗位代表 ECMWF 发布的 CAMS 系统招聘科学软件工程师招聘岗位，使用 NWP 岗位表示笔者当前从事的岗位。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：以下引用部分均来自招聘信息，并使用豆包 AI 翻译成中文。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="招聘信息"&gt;招聘信息&lt;/h2&gt;
&lt;h3 id="核心职责"&gt;核心职责&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;与科学和技术专家合作，设计、开发和支持 CAMS 业务产品的工作流；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWP 岗位在构建 NWP 业务系统 ecFlow 工作流时需要和研发团队密切合作。
比如业务同学需要熟读研发同学使用的流程控制脚本和任务脚本，了解整个系统的运行流程和每个任务的输入输出，研发同学需要和业务同学一同验证业务流程的输出结果。
只有在研发和业务同学紧密合作的情况下，才能快速完成研发到业务转化 (R2O) 的工作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对科学和技术成果进行早期技术质量保证测试；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWP 岗位经常会参与 NWP 系统业务升级更新前的测试工作，尤其是业务化测试相关工作，主要负责实施对 ecFlow 工作流的测试。
部分业务同学也同时会参与 NWP 系统 Shell 运行脚本开发工作。
但基于脚本的测试（集成测试、批量回算等）通常由研发部门承担，有些情况下业务系统升级测试使用脚本而不是 ecFlow 工作流方式完成，大多是因为从研发脚本到业务工作流需要一定时间，无法按时在升级评审前完成 R2O 工作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;确保新开发内容兼容业务需求，具备优化性和可靠性；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从研发到业务的转化工作主要由 NWP 岗位完成。
NWP 岗位在开发/维护 ecFlow 工作流时，大部分时间都在确保研发程序能融入到业务流程中。比如&lt;/p&gt;</description></item><item><title>关于数值天气预报业务系统支撑软件工具发展方向的一些想法</title><link>https://blog.perillaroc.wang/post/2025/04/2025-04-02-thoughts-about-software-tool-strategy-in-cemc/</link><pubDate>Mon, 28 Apr 2025 21:51:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/04/2025-04-02-thoughts-about-software-tool-strategy-in-cemc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表笔者个人观点，文章中引用的相关材料仅用于探讨和交流，不能作为最终事实依据。
关于数值天气预报模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。
如有任何疑问，建议查阅权威资料或咨询相关领域的专家。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文受 ECMWF 技术文档《Software Strategy and Roadmap 2023–2027》启发而撰写，大量内容来自对该技术文档内容的重组。
笔者对该技术文档的翻译参见《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;本文聚焦数值天气预报业务系统 (NWP) 使用的一些支撑软件工具领域，介绍 &lt;strong&gt;笔者个人&lt;/strong&gt; 对 NWP 支撑软件工具相关领域未来一段时间 (1-3年) 发展方向的一些想法。&lt;/p&gt;
&lt;h2 id="范围"&gt;范围&lt;/h2&gt;
&lt;p&gt;本文仅讨论软件工具包，不涉及系统平台。&lt;/p&gt;
&lt;p&gt;软件工具包一般作为一个功能组件可以集成到某个系统或平台中，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NetCDF 库&lt;/li&gt;
&lt;li&gt;wgrib2&lt;/li&gt;
&lt;li&gt;ecFlow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;系统或平台可以提供某种产品或服务，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NWP 业务运行系统&lt;/li&gt;
&lt;li&gt;NWP 业务监控系统&lt;/li&gt;
&lt;li&gt;NWP 中试试验平台&lt;/li&gt;
&lt;li&gt;NWP 数据管理平台&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="指导原则"&gt;指导原则&lt;/h2&gt;
&lt;p&gt;参考 ECMWF 软件发展战略文档中的指导原则。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;软件可重用&lt;/strong&gt;。软件可以在多种环境中复用，比如超算、云平台、个人工作电脑、Jupyter笔记本等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;软件组件化&lt;/strong&gt;。将通用基础功能从各个工具库中抽取出来形成独立的工具组件，方便集成到其他工具中。注重工具与 Python 的集成&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据标准化&lt;/strong&gt;。制定并遵循统一的标准数据结构，提高软件工具之间的互操作性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本管理&lt;/strong&gt;。通过版本库规范开发流程，探索协作开发途径，扩大软件工具的使用范围&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开源发布&lt;/strong&gt;。提供测试用例和用户手册&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="发展方向"&gt;发展方向&lt;/h2&gt;
&lt;h3 id="软件工具领域"&gt;软件工具领域&lt;/h3&gt;
&lt;h4 id="场景"&gt;场景&lt;/h4&gt;
&lt;p&gt;软件工具有两个使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;模式软件&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;模式软件是直接应用到地球系统数值预报模式 (ESM) 业务系统中的软件。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;观测资料检索工具库&lt;/li&gt;
&lt;li&gt;GRIB2 编解码工具库&lt;/li&gt;
&lt;li&gt;绘图工具包&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;支撑与分析工具&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;支撑与分析工具是支撑地球系统数值预报模式研发的软件工具，也包括对模式数据进行分析的工具。
这类工具可能间接应用到业务系统中，例如作为某个工具引用的包。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMADaaS 发布的 music-sdk&lt;/li&gt;
&lt;li&gt;数据准备工具库 reki&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="领域"&gt;领域&lt;/h4&gt;
&lt;p&gt;本文对 NWP 支撑软件工具分为如下领域，按照当前的开发进展进行分类。&lt;/p&gt;</description></item><item><title>超算平台使用miniforge安装conda环境</title><link>https://blog.perillaroc.wang/post/2025/04/2025-04-27-install-conda-in-hpc/</link><pubDate>Sun, 27 Apr 2025 21:47:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/04/2025-04-27-install-conda-in-hpc/</guid><description>&lt;p&gt;单位使用的超算平台从去年某时间起不提供统一管理的 anaconda 环境，本文介绍如何在超算平台使用 miniforge 安装 conda 环境。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;Anaconda 在 &lt;strong&gt;2024 年 3 月 31 日&lt;/strong&gt; 生效的&lt;a href="https://legal.anaconda.com/policies/en/?name=terms-of-service#anaconda-terms-of-service"&gt;服务协议&lt;/a&gt;中新增了对组织使用的具体要求，原文如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2.1 Organizational Use. Your registration, download, use, installation, access, or enjoyment of all Anaconda Offerings on behalf of an organization that has two hundred (200) or more employees or contractors (“Organizational Use”) requires a paid license of Anaconda Business or Anaconda Enterprise. For sake of clarity, use by government entities and nonprofit entities with over 200 employees or contractors is considered Organizational Use. Purchasing Starter tier license(s) does not satisfy the Organizational Use paid license requirement set forth in this Section 2.1. Educational Entities will be exempt from the paid license requirement, provided that the use of the Anaconda Offering(s) is solely limited to being used for a curriculum-based course. Anaconda reserves the right to monitor the registration, download, use, installation, access, or enjoyment of the Anaconda Offerings to ensure it is part of a curriculum. Utilizing Miniconda to pull package updates from the Anaconda Public Repository without a commercial license (if required by the conditions set forth in Section 2 of this Terms of Service) is considered a violation of the Terms of Service.&lt;/p&gt;</description></item><item><title>读书笔记：秦制两千年</title><link>https://blog.perillaroc.wang/post/2025/04/2025-04-06-reading-qin-zhi-liang-qian-nian/</link><pubDate>Sun, 06 Apr 2025 15:41:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/04/2025-04-06-reading-qin-zhi-liang-qian-nian/</guid><description>&lt;h2 id="图书信息"&gt;图书信息&lt;/h2&gt;
&lt;p&gt;《秦制两千年》&lt;/p&gt;
&lt;p&gt;作者: 谌旭彬&lt;/p&gt;
&lt;p&gt;副标题: 封建帝王的权力规则&lt;/p&gt;
&lt;p&gt;出版年: 2021-7&lt;/p&gt;
&lt;h2 id="读书笔记"&gt;读书笔记&lt;/h2&gt;
&lt;p&gt;盛名难副的典型。记得几年前在排行榜上很火，现在看完全本只能说，读书一道众口难调。
看到的豆瓣短评中有提到本书是公众号文章合集，颇有借古讽今的意味，我非常赞同。&lt;/p&gt;
&lt;p&gt;最后一章标题是“清王朝灭亡的原因”，不过介绍得不够详尽，全书结束比较突然，都没有对前文进行更深入的总结，说实话我是没怎么看懂为什么从秦以来到清末两千多年的政治可以用一个“秦制”来概括。
不过作者还写了一本《大变局：晚清改革五十年》，位列豆瓣 2024 年度历史文化图书第 9 名，找时间应该看看，可能会有更详细的描述。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：豆瓣2024年度历史文化图书第 1 名是孙立天的《康熙的红票：全球化中的清朝》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;书中核心观点在于中央政府通过对民众的汲取导致民众生活在水深火热中。
既然从经济领域对政治进行分析，就应该更深入的分析经济关系。
我不了解政治经济学，但也觉得作者忽略了中央政府、地方政府的矛盾，也没有更深入分析官僚阶级、地主阶级与无产阶级之间的经济关系，全书也没有提到国外对国内的影响，仅仅对中央政府一方的批判很难得到无偏见的结论。&lt;/p&gt;
&lt;p&gt;另外，书中示例似乎忽略了历史中的一些标志事件，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;讲了明太祖各种猛政，却没有提及著名的南北榜案&lt;/li&gt;
&lt;li&gt;介绍了东林党却没怎么说东林党争&lt;/li&gt;
&lt;li&gt;介绍清朝没有提到康熙和乾隆的“康乾盛世”，反而举了一个我没听过的“同光中兴”&lt;/li&gt;
&lt;li&gt;书中没怎么提及元朝的事情&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;豆瓣评分两颗星给书中大量篇幅都在用众多的历史资料证明历史上所谓的“盛世”、“改革”都没有什么用。&lt;/p&gt;
&lt;h2 id="书摘"&gt;书摘&lt;/h2&gt;
&lt;p&gt;关于曹魏：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;曹魏之所以能够在汉末、三国的乱世之中胜出，核心原因并不仅仅在于曹操、曹丕个人如何雄才大略，而是他们的手段够狠、够硬、够有效，建立起了比其他军阀更强大的人力、物力的汲取机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;秦制时代的军阀混战有一个非常寻常的道理：谁的手段越狠，谁就越有能力从百姓身上榨取到更多的人力、物力资源，谁就最有可能胜出。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;知识分子旨趣相投，彼此来往，交流议论时事，本无任何过错，给他们扣上一顶“浮华交游”的帽子不过是曹魏打压舆论的惯用手段。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于贞观之治：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当中国土地上的人口从6000万锐减至1000多万，任何智力正常的君主，只要他没有丧心病狂，都可能实现所谓的文景之治或光武中兴。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;官僚吃饱吃好自然不成问题，部曲、奴婢是官僚的私有财产，为了保值，也不会随随便便就被饿死。
所以，要判断贞观之治的含金量，主要得看自耕农和半自耕农过得怎样。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于明太祖：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以常理论，胥吏的势力，上不足以与朱元璋的皇权相比，下不足以抗衡群众运动的汪洋大海，整顿他们本该是一件轻而易举的事情，事实却不然。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于东林党：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;东林党的历史其实可以用一句话来概括：他们试图以制度章程，也就是《大明律》与《皇明祖训》之类的东西来约束皇权，进而维护自己和百姓的利益，却遭到了皇权的残酷镇压。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;当皇权如此蹂躏官僚集团，官僚自不会再视皇权为利益共同体，其消极怠政是必然的，明帝国的统治力因之削弱也是必然。
当民变与外敌同时袭来，官僚集团的怠政，也就是消极于人力、物力的汲取，带给明帝国的伤害会非常直接。
换言之，若真的存在“党争亡国”，那么挑起党争、将政见分歧演变成杀戮的恰是皇帝自己。明神宗如此，明熹宗如此，崇祯也如此。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于同光中兴：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;通过开设新税种并引入新的征税技术，提升了秦制国家的汲取能力。
当可瓜分的蛋糕持续做大时，统治集团的内部矛盾，自然也就被弱化和掩盖了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于秦制：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;秦制的两大基本特征是：&lt;/p&gt;
&lt;p&gt;1．以官僚集团而非封建贵族作为政权的统治基础。
追求普天之下“莫非王土”和“莫非王臣”；官僚集团既是秦制政权的统治基础，又是秦制政权时时防范压制的对象。&lt;/p&gt;
&lt;p&gt;2．施政的核心诉求是尽可能提升人力与物力的汲取强度与总量。
为此，必然致力于消灭一切有影响力的人与组织，消灭对象不但包括民间组织，也包括官僚集团的“朋党化”，简言之就是追求一种散沙化与原子化的扁平社会结构，为此不惜牺牲社会活力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/35356472/"&gt;豆瓣读书页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>论文阅读：ECMWF研究到业务转化R2O流程</title><link>https://blog.perillaroc.wang/post/2025/03/2025-03-16-paper-the-ecmwf-research-to-operations-process/</link><pubDate>Tue, 18 Mar 2025 23:05:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/03/2025-03-16-paper-the-ecmwf-research-to-operations-process/</guid><description>&lt;p&gt;The ECMWF research to operations (R20) process&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;BUIZZA R, ANDERSSON E, FORBES R, et al., 2017. The ECMWF research to operations (R20) process[Z/OL]//ECMWF Technical Memoranda. ECMWF. &lt;a href="https://www.ecmwf.int/node/17549"&gt;https://www.ecmwf.int/node/17549&lt;/a&gt;. DOI:10.21957/m3r9bvg6x.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文翻译自 ECMWF 技术文档 806，发布于 2017 年 7 月。主要介绍 ECMWF 研究到业务转化流程的主要阶段和活动。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：以下“正文”章节内容使用 ChatGPT 和 DeepSeek 翻译自论文，并根据笔者个人理解有所&lt;strong&gt;删改整合&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以下名为“&lt;strong&gt;译注&lt;/strong&gt;”的章节均为笔者添加，阐述笔者对某章节的个人理解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="摘要"&gt;摘要&lt;/h3&gt;
&lt;p&gt;欧洲中期天气预报中心（ECMWF）业务的关键环节之一是“研究到业务” (Research-to-Operations, R2O) 流程，用于升级 IFS 周期 (IFS cycle，即用于预报生产的软件)。
R2O 流程始于一个战略性的 10 年愿景，并最终落实到 IFS 周期的实施。
该流程包括一系列行动，可以概括为六项活动：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;规划&lt;/li&gt;
&lt;li&gt;开发&lt;/li&gt;
&lt;li&gt;测试&lt;/li&gt;
&lt;li&gt;评估&lt;/li&gt;
&lt;li&gt;沟通&lt;/li&gt;
&lt;li&gt;实施&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;R2O 流程涉及计算客观指标以评估模式性能，并与所有关键利益相关者进行沟通。&lt;/p&gt;
&lt;p&gt;本文重点介绍了 ECMWF R2O 流程的主要阶段和活动。&lt;/p&gt;</description></item><item><title>更新ecFlow系统支持分钟级产品</title><link>https://blog.perillaroc.wang/post/2025/03/2025-03-13-update-ecflow-system-to-generate-minute-level-product/</link><pubDate>Sat, 15 Mar 2025 18:06:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/03/2025-03-13-update-ecflow-system-to-generate-minute-level-product/</guid><description>&lt;p&gt;本文介绍如何对 MESO 后处理子系统进行改造以生成分钟级数据和图片产品。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表笔者个人观点，文章中引用的相关材料仅用于探讨和交流，不能作为最终事实依据。
关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。如有任何疑问，建议查阅权威资料或咨询相关领域的专家。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;CEMC 运行的 MESO 系统模式间隔 1 小时输出，生成逐 1 小时产品。
下图展示了 MESO 系统生成的一幅图片产品。
图片的左下角和右下角标注了产品对应的起报时次 (2025031200)、预报时效 (24h) 和预报时刻 (2025031300)，预报时效和预报时刻都精确到小时。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2025/workflow/2025-03-miniute-level-meso/meso-1hr-product-example.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 MESO 图片产品示例，可以通过如下网址访问 &lt;a href="http://www.nmc.cn/publish/area/china/hws_0000.html"&gt;NMC 网站&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;CEMC 也同时协助多个区域中心部署小区域 MESO 系统。
其中一个区域系统要求提供前 3 小时逐 10 分钟的输出。&lt;/p&gt;
&lt;p&gt;因 CEMC 的 MESO 系统尚未生成分钟级产品，本文记录笔者目前对区域部署的 MESO 后处理子系统的改造尝试，使其支持分钟级模式输出数据，生成分钟级数据和图片产品。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文介绍方案是在较短任务期限内形成的临时解决方案，仅针对当前任务需求进行改造，未来会进一步开发更具有通用性的解决方案。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文首先介绍现有 MESO 后处理子系统的关键技术细节，然后介绍支持分钟级产品的改造方案，最后介绍具体实现。&lt;/p&gt;
&lt;h2 id="现状"&gt;现状&lt;/h2&gt;
&lt;p&gt;MESO 系统由三个独立的子系统构成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;观测资料检索子系统：检索并预处理模式需要的观测资料，在模式预报子系统启动前运行&lt;/li&gt;
&lt;li&gt;模式预报子系统：主要运行资料同化和模式积分任务&lt;/li&gt;
&lt;li&gt;后处理子系统：主要运行数据产品和图片产品生成任务，与模式预报子系统同时运行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;模式预报子系统的模式积分任务运行模式积分程序生成一段时间内的预报结果，比如 MESO 系统 00/12 时次预报未来三天的天气。
模式程序运行过程中每积分一定时长会输出表示该时刻预报结果的二进制格式文件，MESO 系统每积分一个小时会输出一个模式面 modelvar 文件和一个等压面 postvar 文件。&lt;/p&gt;
&lt;p&gt;后处理子系统的数据检查任务监控模式预报子系统模式输出的 modelvar 文件，每当一个时效 modelvar 文件生成，则会触发对应时效的产品制作任务。&lt;/p&gt;
&lt;p&gt;下图展示了 MESO 后处理子系统的运行流程，由数据产品和图片产品两个子流程构成。&lt;/p&gt;</description></item><item><title>数值天气预报模式系统运维分级方案示例</title><link>https://blog.perillaroc.wang/post/2025/03/2025-03-12-an-example-maintenance-level-for-nwp-systems-in-cemc-oper/</link><pubDate>Wed, 12 Mar 2025 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2025/03/2025-03-12-an-example-maintenance-level-for-nwp-systems-in-cemc-oper/</guid><description>&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;随着数值天气预报业务的持续发展，加上即将进入到新老模式双核运行的过渡时期，可以预计需要集成和维护的系统将在一段时间内持续增加。
在集成运维团队人员无法相对应增长的情况下，如何合理安排有限的人力依序开展工作成为一个必须要考虑的问题，以促进团队的可持续发展。&lt;/p&gt;
&lt;p&gt;本文以假想的数值天气预报业务系统集成与运维团队 (CEMC-OPER) 为例，介绍一种对数值天气预报模式系统进行运维分级的方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注&lt;/strong&gt;：本文&lt;strong&gt;仅代表&lt;/strong&gt;笔者本人观点，&lt;strong&gt;不表示&lt;/strong&gt;该方案在 CEMC 中实际应用。
如果想了解 CEMC 的具体实践，请咨询 CEMC 相关部门。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参与人员"&gt;参与人员&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CEMC-OPER 值班团队：参与运维轮值&lt;/li&gt;
&lt;li&gt;CEMC-OPER 系统建设团队：系统运行流程开发人员，建设 ecFlow 运行系统&lt;/li&gt;
&lt;li&gt;CEMC-OPER 外协运维团队：参与 7x24 运维值班&lt;/li&gt;
&lt;li&gt;CEMC 业务系统研发团队：系统程序开发人员&lt;/li&gt;
&lt;li&gt;外单位业务系统研发团队：外单位的系统程序开发人员&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="运维岗位"&gt;运维岗位&lt;/h2&gt;
&lt;p&gt;运维岗位分为三类。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：实际上有四个岗位，为了缩减岗位种类，二线岗位包含两种角色。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="一线"&gt;一线&lt;/h3&gt;
&lt;p&gt;7 x 24 小时在岗，运维值班员&lt;/p&gt;
&lt;p&gt;负责监控业务系统运行情况，并处理常见故障。
发现故障后，先尝试处理故障，如果无法处理，联系二线运维。&lt;/p&gt;
&lt;p&gt;由 CEMC-OPER 外协运维团队承担，特殊情况下由 CEMC-OPER 值班团队承担。&lt;/p&gt;
&lt;h3 id="二线"&gt;二线&lt;/h3&gt;
&lt;p&gt;7 x 24 小时响应，运维领班&lt;/p&gt;
&lt;p&gt;响应一线运维，负责处理复杂故障，分析故障原因。有必要时联系二线+和三线人员。&lt;/p&gt;
&lt;p&gt;由 CEMC-OPER 值班团队承担。&lt;/p&gt;
&lt;h3 id="二线-1"&gt;二线+&lt;/h3&gt;
&lt;p&gt;较少情况下响应，系统建设者&lt;/p&gt;
&lt;p&gt;分析系统故障原因，处理系统 BUG，执行系统更新。&lt;/p&gt;
&lt;p&gt;由 CEMC-OPER 系统建设团队承担。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：CEMC-OPER 的值班团队与系统建设团队有较大重叠，二线可以同时承担一部分二线+职责。
本段介绍的岗位仅适合运行系统建设与运维值班由同一团队承担的情况。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="三线"&gt;三线&lt;/h3&gt;
&lt;p&gt;罕见情况下响应，程序开发者&lt;/p&gt;
&lt;p&gt;分析程序故障原因，处理程序 BUG，开发程序补丁。&lt;/p&gt;
&lt;p&gt;由 CEMC 业务系统研发团队和外单位业务系统研发团队承担。&lt;/p&gt;
&lt;h2 id="运维优先级"&gt;运维优先级&lt;/h2&gt;
&lt;p&gt;分为 5 个级别，从高到低分别是：&lt;/p&gt;</description></item><item><title>2024年工作总结</title><link>https://blog.perillaroc.wang/post/2024/12/2024-12-19-summary-of-working-in-cemc/</link><pubDate>Thu, 23 Jan 2025 16:28:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/12/2024-12-19-summary-of-working-in-cemc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自 2024 年 12 月 18 日个人工作汇报做的 PPT。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="系统建设"&gt;系统建设&lt;/h2&gt;
&lt;p&gt;2024 年共新建 12 套系统，更新 4 套系统，合作新建 3 套系统。
下图展示了在国家级超算平台 4 个子系统中我负责维护和参与维护的系统，将近 20 套，当然部分系统实际上是同一套代码的多次部署。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/summary/2024-summary/systems-in-2024.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 国家级气象超算平台 4 个子系统中负责/参与维护的系统&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;在系统建设方面的年度热词是“一周”，下面我介绍三项被要求在一周内完成的任务。&lt;/p&gt;
&lt;h3 id="tym-v4-流程建设"&gt;TYM V4 流程建设&lt;/h3&gt;
&lt;p&gt;7月15日-19日-26日&lt;/p&gt;
&lt;p&gt;第一项任务是为 CMA-TYM V4.0 版本新建运行流程。&lt;/p&gt;
&lt;p&gt;一共新建 2 套系统，更新 1 套系统。分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TYM V4 + NCEP GFS (with POST)，完成 3 个月实时运行&lt;/li&gt;
&lt;li&gt;TYM V4 + CMA-GFS (with POST)，完成 2024 年度台风回算&lt;/li&gt;
&lt;li&gt;TYM V3.3 + CMA-GFS (GRIB2 驱动)，完成 XX 演练&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/summary/2024-summary/tym-v3.3.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CMA-TYM V3.3 系统的两个配置，NCEP-GFS驱动 / CMA-GFS 驱动&lt;/em&gt;&lt;/p&gt;</description></item><item><title>使用Modulefile加载Conda环境</title><link>https://blog.perillaroc.wang/post/2024/11/2024-11-08-load-conda-env-in-modulefiles/</link><pubDate>Fri, 08 Nov 2024 21:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/11/2024-11-08-load-conda-env-in-modulefiles/</guid><description>&lt;p&gt;本文介绍如何在 Environment Modules 管理软件的系统中实现使用 module 加载 conda 环境。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;笔者使用的一台 HPC 上安装了 conda 环境，并使用 module 进行管理。&lt;/p&gt;
&lt;p&gt;conda 环境的 modulefile 类似下面的代码，设置了一些环境变量，并将 &lt;code&gt;conda&lt;/code&gt; 所在的目录添加到环境变量 &lt;code&gt;PATH&lt;/code&gt; 中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-tcl" data-lang="tcl"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setenv CONDA_SHLVL &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setenv _CE_M &lt;span style="color:#66d9ef"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setenv CONDA_EXE &lt;span style="color:#f92672"&gt;/&lt;/span&gt;g1&lt;span style="color:#f92672"&gt;/&lt;/span&gt;app&lt;span style="color:#f92672"&gt;/&lt;/span&gt;apps&lt;span style="color:#f92672"&gt;/&lt;/span&gt;anaconda_gpu&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin&lt;span style="color:#f92672"&gt;/&lt;/span&gt;conda
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setenv CONDA_PYTHON_EXE &lt;span style="color:#f92672"&gt;/&lt;/span&gt;g1&lt;span style="color:#f92672"&gt;/&lt;/span&gt;app&lt;span style="color:#f92672"&gt;/&lt;/span&gt;apps&lt;span style="color:#f92672"&gt;/&lt;/span&gt;anaconda_gpu&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin&lt;span style="color:#f92672"&gt;/&lt;/span&gt;python
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;setenv _CE_CONDA &lt;span style="color:#66d9ef"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;prepend-path PATH &lt;span style="color:#f92672"&gt;/&lt;/span&gt;g1&lt;span style="color:#f92672"&gt;/&lt;/span&gt;app&lt;span style="color:#f92672"&gt;/&lt;/span&gt;apps&lt;span style="color:#f92672"&gt;/&lt;/span&gt;anaconda_gpu&lt;span style="color:#f92672"&gt;/&lt;/span&gt;condabin:&lt;span style="color:#f92672"&gt;/&lt;/span&gt;g1&lt;span style="color:#f92672"&gt;/&lt;/span&gt;app&lt;span style="color:#f92672"&gt;/&lt;/span&gt;apps&lt;span style="color:#f92672"&gt;/&lt;/span&gt;anaconda_gpu&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载该模块后，可以使用 conda 命令，但无法直接激活 env 环境。
执行 &lt;code&gt;conda activate base&lt;/code&gt; 命令后，会提示需要使用 &lt;code&gt;conda init&lt;/code&gt; 初始化 shell 环境。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$conda activate base

CommandNotFoundError: Your shell has not been properly configured to use &amp;#39;conda activate&amp;#39;.
To initialize your shell, run

 $ conda init &amp;lt;SHELL_NAME&amp;gt;

Currently supported shells are:
 - bash
 - fish
 - tcsh
 - xonsh
 - zsh
 - powershell

See &amp;#39;conda init --help&amp;#39; for more information and options.

IMPORTANT: You may need to close and restart your shell after running &amp;#39;conda init&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行 &lt;code&gt;conda init bash&lt;/code&gt; 后，会在 &lt;code&gt;~/.bashrc&lt;/code&gt; 中添加如下代码：&lt;/p&gt;</description></item><item><title>GRIB2文件不同打包方式的加载速度对比</title><link>https://blog.perillaroc.wang/post/2024/10/2024-10-19-grib-notebook-load-speed-with-different-grib2-packing-type/</link><pubDate>Thu, 07 Nov 2024 21:50:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/10/2024-10-19-grib-notebook-load-speed-with-different-grib2-packing-type/</guid><description>&lt;blockquote&gt;
&lt;p&gt;注：本文是对 2022 年博文《&lt;a href="https://blog.perillaroc.wang/post/2022/03/2022-03-13-grib-notebook-load-speed-with-different-grib2-packing-type/"&gt;不同打包方式下GRIB2文件加载速度对比：简单打包与JPEG压缩&lt;/a&gt;》的更新。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GRIB2 格式文件支持使用不同方式保存要素场数据，可以使用二维数组的一维展开，也可以使用类似 JPEG、PNG 等图片格式对二维数据进行压缩。&lt;/p&gt;
&lt;p&gt;本文介绍不同打包方式下从 GRIB2 文件中加载要素场的速度。&lt;/p&gt;
&lt;h2 id="打包方式"&gt;打包方式&lt;/h2&gt;
&lt;p&gt;GRIB2 支持多种打包方式，下表是 GRIB2 标准中的 CODE TABLE 5.0，列出了当前 WMO 标准支持的打包方式（参考 &lt;a href="https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table5-0.shtml"&gt;NCEP GRIB2 文档&lt;/a&gt;，或 &lt;a href="https://codes.ecmwf.int/grib/format/grib2/ctables/5/0/"&gt;ECMWF GRIB2 文档&lt;/a&gt;）：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;编码&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;Grid Point Data - Simple Packing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;Matrix Value at Grid Point - Simple Packing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;Grid Point Data - Complex Packing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;Grid Point Data - Complex Packing and Spatial Differencing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;Grid Point Data - IEEE Floating Point Data (see Template 5.4)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;40&lt;/td&gt;
					&lt;td&gt;Grid point data - JPEG 2000 code stream format&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;41&lt;/td&gt;
					&lt;td&gt;Grid point data - Portable Network Graphics (PNG)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;42&lt;/td&gt;
					&lt;td&gt;Grid point data - CCSDS recommended lossless compression&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;50&lt;/td&gt;
					&lt;td&gt;Spectral Data - Simple Packing (see Template 5.50)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;51&lt;/td&gt;
					&lt;td&gt;Spectral Data - Complex Packing (see Template 5.51)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;53&lt;/td&gt;
					&lt;td&gt;Spectral data for limited area models - complex packing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;61&lt;/td&gt;
					&lt;td&gt;Grid Point Data - Simple Packing With Logarithm Pre-processing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;200&lt;/td&gt;
					&lt;td&gt;Run Length Packing With Level Values&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不同中心生成的 GRIB2 数据使用不同的打包方式：&lt;/p&gt;</description></item><item><title>视界：欧洲天气云正式投入运营</title><link>https://blog.perillaroc.wang/post/2024/08/2024-08-21-view-european-weather-cloud-now-operational/</link><pubDate>Sat, 24 Aug 2024 07:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/08/2024-08-21-view-european-weather-cloud-now-operational/</guid><description>&lt;p&gt;本文翻译自 ECMWF 的一篇通讯文章，介绍欧洲天气云 (European Weather Cloud) 的现状。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The European Weather Cloud is now operational&lt;/p&gt;
&lt;p&gt;by Xavier Abellan, Vasileios Baousis, Ricardo Correa, Roberto Cuccu, Cristina Duma, Charalampos Kominos, Samuel Langlois, Umberto Modigliani&lt;/p&gt;
&lt;p&gt;in ECMWF Newsletter Number 180 - Summer 2024 (Published in July 2024)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/newsletter/180/computing/european-weather-cloud-now-operational"&gt;https://www.ecmwf.int/en/newsletter/180/computing/european-weather-cloud-now-operational&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以下&lt;strong&gt;正文&lt;/strong&gt;部分使用 ChatGPT 和文心一言翻译自原文，并根据笔者理解略有修改。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;欧洲天气云 (European Weather Cloud, EWC) 是由 ECMWF 和 EUMETSAT 共同运营的社区云计算平台。
该概念由 ECMWF 提出，建立在 ECMWF 为其成员国和合作国提供计算访问方面的丰富经验之上，例如通过 ecgate 服务。
EWC 促进数据访问，提高数据处理能力，并推动 ECMWF 和 EUMETSAT 成员国与合作国的国家气象和水文服务机构 (NMHSs) 以及研究人员之间的新型合作形式。
该计划始于 2019 年，通过试点阶段为当前服务奠定基础。
试点阶段的目标包括：&lt;/p&gt;</description></item><item><title>CEMC数值天气预报业务系统建设介绍（2023版）</title><link>https://blog.perillaroc.wang/post/2024/02/2024-02-06-cemc-systems-build-intro/</link><pubDate>Thu, 13 Jun 2024 16:49:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/02/2024-02-06-cemc-systems-build-intro/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自笔者 2023 年 8 月 7 日参与单位新职工培训的 PPT《CEMC 业务系统介绍》。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表笔者个人观点，所选材料截止时间为 2023 年 8 月，不代表当前的业务系统建设现状。
CEMC 已于 2024 年 5 月完成内设机构改革，本文内容已不再完全适用。
如果想了解最新信息，请咨询 CEMC 相关部门。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="1-业务系统简介"&gt;1. 业务系统简介&lt;/h2&gt;
&lt;h3 id="11-单位简介"&gt;1.1 单位简介&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本节内容不是最新的机构设置情况。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CEMC 于 2021 年 10 月 1 日成立，设有 3 个职能处室和 9 个业务处室。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/tutorial/02-06-systems-build-intro/cemc-orgs.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CEMC 组织架构图，来自 &lt;a href="https://cemc.cma.cn/about.html"&gt;CEMC 官网&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;我来自业务运行室的系统集成技术科。业务室的主要职责有三项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;业务集成与运行&lt;/strong&gt;：发展地球模式系统的业务化集成和运行技术&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产品应用技术&lt;/strong&gt;：发展模式系统后处理技术并拓展产品应用能力&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模式研发支撑技术&lt;/strong&gt;：发展支撑地球系统模式协同中试的信息技术&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="12-数值天气预报业务系统"&gt;1.2 数值天气预报业务系统&lt;/h3&gt;
&lt;p&gt;业务运行室目前负责建设并维护 CEMC 的数值天气预报业务系统，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确定性模式&lt;/li&gt;
&lt;li&gt;集合预报模式&lt;/li&gt;
&lt;li&gt;环境模式与系统&lt;/li&gt;
&lt;li&gt;产品系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下图是业务运行室目前负责维护的业务系统。
图中黄色部分是 5 个以 GRAPES 模式为核心的数值天气预报业务系统，包括 3 个确定性模式和 2 个集合预报模式，绿色部分是专业数值预报业务系统，蓝色是产品系统。
其中特殊服务保障系统和大气扩散应急响应模式系统因涉及模式较多而未绘制与其它系统的连接线。
另外，该图仅是由业务运行室负责维护的业务系统，不包含其他处室维护的业务系统和实时系统，例如气候模式由集合室和耦合室维护，检验诊断系统由评估室维护。&lt;/p&gt;</description></item><item><title>ECMWF软件战略和路线图译注：1.1 资源</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-01/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-01/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#11-资源"&gt;1.1 资源&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;p&gt;译者比较关注 ECMWF 如何处理自研和外包的关系，比如是否通过类似工程项目之类的方式开发软件工具，可惜一直没有找到相关材料。
仅在之前的一篇通讯文章中看到 ECMWF 正在雇用公司开发 IFSHub，参考《&lt;a href="https://blog.perillaroc.wang/post/2021/04/2021-04-29-view-ifshub-a-new-way-to-work-with-ifs-experiments/"&gt;视界：IFShub - 开展IFS试验的新方式&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;CEMC 内部项目侧重于对模式系统软件的开发，而非模式类软件开发项目一般通过工程或外协项目的方式提供资源。
所以一提到非模式类的软件或者平台，就需要考虑如何利用外拨经费项目来实现开发。
从译者过去的经验来看，分散组织独立开发的软件项目本身往往不会关注软件之间的可复用性和互操作性，最终影响项目成果的适用范围。
另外，由承建商引入的各式各样的基础设施架构也会增加维护成本，重复开发的相同功能的组件也会降低对资源的使用效益。&lt;/p&gt;
&lt;p&gt;一个听说的建议方案是由首席科学家负责把控整体技术方案架构，实现对不同外协项目的整合。&lt;/p&gt;
&lt;p&gt;一个正在实施的方案是将不同软件工具集成到同一个平台中，即 CEMC &lt;a href="https://www.cma.gov.cn/2011xwzx/2011xqxxw/2011xqxyw/202308/t20230809_5703048.html"&gt;科创平台&lt;/a&gt;中，确保软件开发项目成果能得到应用。
该平台是 CEMC 版的 IFSHub，也类似下文提到的 ECMWF 创新平台。&lt;/p&gt;
&lt;p&gt;译者正在谋划面向模式数据分析和可视化开发一套 Python 支撑工具集，由业务应用开始并逐步发展到研发应用。
第一步将从协助部门同事申请中心内部青年基金课题开始，并借助业务升级的契机展示全新 Python 工具软件栈的优势，进一步争取更多的资源支持。&lt;/p&gt;</description></item><item><title>ECMWF软件战略和路线图译注：1.3 开放开发</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-03/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-03/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#13-开放开发"&gt;1.3 开放开发&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;p&gt;译者观察到 2023 年 ECMWF 大幅提高软件工具的开源速度，释放了一系列以往内部使用的核心组件，例如 FDB，MultIO 等，ECMWF 甚至在考虑将 IFS 的部分组件开源。&lt;/p&gt;
&lt;p&gt;CMA 更多关注代码的内部共享。目前，CMA 已经建立 METCODE 代码管理协作共享平台 (参见文献 [1])，作为内部代码共享 Git 版本管理仓库，类似于 ECMWF 中心内部搭建的 BitBucket 服务。
CEMC 正在将整体代码库从 Perforce 迁移到 METCODE 的 Git 仓库中。&lt;/p&gt;
&lt;p&gt;虽然在研发方面越来越多地强调合作共享，在系统软件中也使用大量的开源组件，但开源一直没有成为内部的主流思想。
译者在开源社区 Github 中仅观察到两个持续开源的内部项目组，即 &lt;a href="https://github.com/nmcdev"&gt;nmcdev&lt;/a&gt; 和 &lt;a href="https://github.com/meteoinfo"&gt;meteoinfo&lt;/a&gt;。
这两个小组的开源软件工具也在业界得到了广泛的应用。
另外，译者也非常高兴地看到 CMA 正在参与 WMO WIS2.0 开源项目 &lt;a href="https://github.com/wmo-im/wis2box"&gt;wis2box&lt;/a&gt; 的开发工作。
未来一定会涌现出越来越多的开源项目。&lt;/p&gt;
&lt;p&gt;作为一个坚定的开源支持者，译者一直鼓吹将工具类软件开源发布，也将工作开发的绝大部分软件工具以 &lt;a href="https://github.com/cemc-oper"&gt;cemc-oper&lt;/a&gt; 小组的形式在 Github 上开源。
但开源不仅是将源码放到网站上而已，一个成熟的开源项目需要完整的文档、持续的更新和适时的推广，这也是译者开发项目没能从个人项目演变为开源项目的问题所在。
下一步，译者将继续坚守开源理念，努力将个人的玩具类项目发展为真正的社区项目。&lt;/p&gt;
&lt;h3 id="参考文献"&gt;参考文献&lt;/h3&gt;
&lt;p&gt;[1]. 赵春燕,王彬,孙婧,常飚,胡江凯,周斌.基于GIT的气象数值模式代码管理平台METCODE[J].气象科技,2021,49(4):535~541&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;CEMC Oper 小组 Github 主页：&lt;a href="https://github.com/cemc-oper"&gt;cemc-oper&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ECMWF软件战略和路线图译注：1.4 安全性</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-04/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-04/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#14-安全性"&gt;1.4 安全性&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;p&gt;安全是软件开发必须要考虑的关键问题之一。本节从四个方面介绍了安全方面的策略，包括软件开发过程的安全性、数据的安全性、对外服务的安全与代码安全。&lt;/p&gt;
&lt;p&gt;国际主要气象中心都在使用版本控制系统管理数值预报模式软件开发工作。
CEMC 十多年来一直使用 Perforce 管理模式软件的开发过程，第一次提交记录是 2010 年 8 月 10 日，截止 2023 年底已有 2 万 6 千多条提交记录。
不过，因为 Perforce 的授权用户数量限制，代码提交以组为单位进行，无法追溯到个人。
再加上 Perforce 授权到期后没有进一步采购计划，考虑到 ECMWF 已经从 Perforce 切换到 Git，最终决定将模式代码库从 Perforce 迁移到 Git。
CMA 最新建设的 Metcode 版本管理系统与统一身份认证系统集成，可以为每个研发人员提供个人账户，也就能实现对个人作者的追溯。
但软件开发不仅仅是引入一个新的工具就能解决问题，更是一个管理问题，如何将上百人团队的代码成果集成到一个软件系统中将极大考验对软件开发过程的管理水平。
CEMC 仍在探索适合自己的模式系统软件版本管理策略，正在将代码仓库从 Perforce 切换到 Git，面临开发模式从集中式管理到分支式管理的演变，并逐步推进业务系统的代码版本管理。&lt;/p&gt;
&lt;p&gt;本节提到的数据安全同样是 CMA 关注的重点领域。
CMA 对数据流出的管理非常严格，有力地保障了国家安全和知识产权。
不过也带来另一个问题，获取 CMA 制作的数据产品的门槛非常高，往往需要严格的身份验证。
译者观察到针对 CMA 数据的开源软件很少配置自动测试工作流，包括译者自己开发的项目也有同样的问题，原因之一就是很难从外部获取 CMA 的开放数据，导致无法构建针对特定数据的测试工作流。
本节提到的方法可以借鉴，比如提供特殊处理过的测试数据并使用版本控制系统管理测试数据。
译者认为随着越来越多 CMA 主导开源项目的逐步涌现，最终会找到一种提供测试数据的合理方案。&lt;/p&gt;</description></item><item><title>ECMWF软件战略和路线图译注：1.5 软件开发原则与实践</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-05/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-01-05/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#15-软件开发原则与实践"&gt;1.5 软件开发原则与实践&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;p&gt;精益软件开发七原则（来自&lt;a href="https://zh.wikipedia.org/wiki/%E7%B2%BE%E7%9B%8A%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91"&gt;wiki&lt;/a&gt;，顺序可能与原文所引不同)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消除浪费&lt;/li&gt;
&lt;li&gt;增强学习&lt;/li&gt;
&lt;li&gt;尽量延迟决定&lt;/li&gt;
&lt;li&gt;尽快发布&lt;/li&gt;
&lt;li&gt;下放权力&lt;/li&gt;
&lt;li&gt;嵌入质量&lt;/li&gt;
&lt;li&gt;全局优化&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ECMWF软件战略和路线图译注：2 软件路线图</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-02-00/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-02-00/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#2-软件路线图"&gt;2 软件路线图&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;h3 id="现状"&gt;现状&lt;/h3&gt;
&lt;p&gt;CEMC 同样运行多套数值天气预报模式业务系统，从全球到区域，从确定性模式到集合预报模式，从大气模式到大气化学、海洋等专业模式。
下图以 CMA-GFS 为例介绍 CEMC 的业务系统工作流。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2023/paper/2023-08-ecmwf-software-strategy/cemc-workflow.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CMA-GFS模式业务系统的工作流，包含 CEMC、NMIC、NMC 等单位的多个系统&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;与 IFS 类似，CMA-GFS 的工作流同样包含从观测资料获取到最终的产品分发全流程。
但与 ECMWF 作为一个实体完全控制 IFS 全部工作流不同的是，CMA-GFS 工作流由 CMA 内部的多个单位共同完成。
在上图所示的工作流中，观测资料获取、产品分发和 HPC 管理由 NMIC 承担，预报产品及服务由 NMC 完成，而 CEMC 负责 CMA-GFS 的资料预处理、同化、模式积分、后处理和部分产品的制作。
实际上，更完整的工作流还包括上下游的更多单位，比如 CMAMOC 处理雷达等观测资料，NSMC 处理卫星观测，PSMC 负责提供对外服务等等。
分散组织的工作流有利于不同实体专注于工作流的特定环节而开展针对性的攻关，但带来包括重复建设、兼容性差等一系列问题。&lt;/p&gt;
&lt;h3 id="集约化"&gt;集约化&lt;/h3&gt;
&lt;p&gt;CMA 多年来一直推动对业务系统的集约化整合，早在 2018 年就发布《气象信息系统集约化管理办法》[1]，提出“统筹规划、统一标准、集约高效、充分共享、安全优先”的原则，并确定建设信息基础设施云平台和气象大数据云平台。
经过多年的建设和试运行，已经建成并业务化一系列“天”字系列系统，包括气象综合业务实时监控系统“&lt;strong&gt;天镜&lt;/strong&gt;”（2020 年）[2]，气象大数据云平台“&lt;strong&gt;天擎&lt;/strong&gt;”（2021 年）[3]，综合气象观测数据质量控制与产品业务系统“&lt;strong&gt;天衡天衍&lt;/strong&gt;”（2024 年）[7]。
并在 2022 年成立国家级气象软件工程企业[4]，并发布《气象业务软件统筹发展工作方案（2022—2025年）》[5]，在 2023 年发布《气象业务软件组件化开发指南（2023版）》[6]。
2024 年 CMA 联合发改委发布《关于统筹集约建设气象业务软件的指导意见》，&lt;em&gt;“明确气象业务软件采用以地球系统大数据平台为统一‘大平台’，以组件构建起支撑核心业务的‘大系统’，发展适应不同业务领域、不同业务层级用户需求的定制化‘多应用’的‘大平台、大系统、多应用’总体架构，实现气象业务系统的‘设施统筹、平台统一、数据统管、系统集成’，最终形成统一规划设计、严格技术标准、组件众创共享、功能高效迭代的气象业务软件发展新格局”&lt;/em&gt;[8]。
综上所述，CMA 以&lt;strong&gt;气象大数据云平台&lt;/strong&gt;及其进阶版&lt;strong&gt;地球系统大数据云平台&lt;/strong&gt;为基石完成对业务系统的集约化整合目标，并通过组件化的技术方案来实现单平台多应用的总体架构。&lt;/p&gt;
&lt;p&gt;从上图来看，无论是工作流中的观测资料获取还是后端的产品服务和预报，都已经形成一系列软件系统，包括具有较长历史的 CTS 和 Micaps，以及近年来业务化的 CMADaaS。
而 CEMC 的工作流完成运行在 HPC 上，采用以数值预报模式为核心的组织方式，每个模式系统的工作流之间相互独立，仅有少部分模块共享，因此也就没有形成相对独立的软件系统。
这种方式适合在 HPC 上运行的工作流，各系统可以独立开发和部署，一个系统的变更操作也基本不会影响其他业务系统，降低了更新的难度，也节省了大量的测试时间。
但 HPC 上的业务系统构建策略不一定能完全适应集约化平台 CMADaaS，如果依然采用以模式为核心的工作流，则需要维护的业务系统将会成倍增加，也不太符合组件化的技术方案。&lt;/p&gt;</description></item><item><title>ECMWF软件战略和路线图译注：2.2 软件栈重构</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-02-02/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-02-02/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#22-软件栈重构"&gt;2.2 软件栈重构&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;h3 id="现状"&gt;现状&lt;/h3&gt;
&lt;p&gt;CEMC 基于自主知识产权的 GRAPES 模式已经建立一整套完备的数值天气预报业务体系，包括从全球到区域，从确定性预报到集合预报等 5 套业务系统[1]。
经过多年的系统开发也逐渐形成了一定的软件栈，为不同的业务系统提供支撑。&lt;/p&gt;
&lt;p&gt;下图列出了译者了解的部分软件栈，包括 CEMC 内部开发的工具库，CMA 内部平台，以及一些开源库。
图中列出的软件栈主要集中到模式的前端和后端，即观测资源检索和模式数据处理和产品制作。
注意，图中不包括集成到 GRAPES 模式代码库中的组件，也不包括一些仅在内部有限范围内使用的软件平台。
另外，译者没有详细调研内部开发的所有软件，所以会有所遗漏。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2023/paper/2023-08-ecmwf-software-strategy/cemc-non-model-software-current.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CEMC 非数值模式组件的软件栈，不包含内部使用的一些 Web 软件平台。其中橙色为 CMA 系统内其他单位开发，蓝色为开源软件。&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="数据编解码"&gt;数据编解码&lt;/h4&gt;
&lt;p&gt;数据编解码层的核心工具是具有十多年开发历史的 GRIB 编解码工具库 grib-util。
该工具库已应用到所有以 GRAPES 模式为核心的业务系统中，每天生成 CMA 天气预报模式 GRIB2 格式数据产品。
在早期版本，grib-util 库使用 ECMWF 开发的 GRIB-API 实现对 GRIB2 格式的编解码，在 2023 年发的最新版本 V10.0 中，首次摆脱了对 GRIB-API 的替代，形成了具有完全自主知识产权的模式产品编解码库，已应用到最新的 CMA-MESO 1KM 系统中，并将在后续升级中应用到其他业务系统中。&lt;/p&gt;
&lt;p&gt;数据编解码层的另一个工具是用于从 CMADaaS 检索观测资料的工具库 get-cmadaasdata。
该工具使用 Fortran 编写，是对 CMADaaS MUSIC 接口 Fortran SDK的封装。
该软件最早通过工程项目由项目承建公司开发，由 CEMC 前身 NWPC 维护，并通过后续工程项目支持进行功能扩展和完善。
在 CEMC 成立后，该工具的维护主体从研发部门逐步转移到译者所在的业务部门，也逐步带来了维护成本的显著上升，也坚定了译者对核心业务软件自研的认识。
软件更新需要首先验证结果的正确性，在缺少自动测试而必须人工验证的情况下，而如果开发者无法独立进行验证，则会因为需要协调专业人员进行验证而导致开发成本显著增加。
部门也尚未找到完善的更新维护方案，当然原因比较复杂，这里仅从译者自身角度出发来尝试说明一些问题。
最重要的一点是我不会 Fortran 编程，工作重点是开发 Python 工具软件，所以缺乏足够的动力仅仅因为维护现有工具类软件而去学习一门全新的编程语言；
另外，我在工程项目的整个周期中都没有参与其中，对该工具的技术路线也完全没有兴趣，也就没有必要在工程项目结束后接手“&lt;em&gt;遗留软件&lt;/em&gt;”的后续维护工作。
正如本篇技术报告多次提到的维护成本问题，依赖项目承建方开发的软件一定要考虑后续维护的问题，不能只停留在应该做什么这一层，而需要进一步考虑怎么做的问题。
当然，作为部门承担的任务，get-cmadaasdata 目前也在持续维护中。
不过，部门已经开始使用 Python 重新编写观测资料检索工具库，并计划完全替代 Fortran 版本的 get-cmadaasdata，从而解决这一技术债务。&lt;/p&gt;</description></item><item><title>ECMWF软件战略和路线图译注：2.3 数据编解码库</title><link>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-02-03/</link><pubDate>Wed, 12 Jun 2024 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/ecmwf-software-strategy/notes-02-03/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文为《&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/"&gt;论文阅读：ECMWF软件战略和路线图2023-2027&lt;/a&gt;》的译注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="原文"&gt;原文&lt;/h2&gt;
&lt;p&gt;译注段落：&lt;a href="https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/#23-数据编解码库"&gt;2.3 数据编解码库&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="译注"&gt;译注&lt;/h2&gt;
&lt;h3 id="现状"&gt;现状&lt;/h3&gt;
&lt;p&gt;模式数据主要分为分为模式输入的观测资料数据和模式输出的格点数据两大类。
CEMC 在数据编解码方面开展了持续的研发，模式输出的格点数据已统一编码为 GRIB2 格式，并正在开展观测资料格式统一相关工作。&lt;/p&gt;
&lt;h4 id="格点数据"&gt;格点数据&lt;/h4&gt;
&lt;p&gt;CEMC 格点数据编解码的核心工具是具有十多年开发历史的 GRIB 编解码工具库 grib-util。
该工具库已应用到所有以 GRAPES 模式为核心的业务系统中，用于每天制作 CMA 天气预报模式 GRIB2 格式的数据产品。&lt;/p&gt;
&lt;p&gt;grib-util 由 Fotran 编写，提供 Fotran 库、命令行工具。
在早期版本，grib-util 库使用 ECMWF 开发的 GRIB-API 实现对 GRIB2 格式的编解码。
需要使用 GRIB-API 的 definition 表格定义文件，以及一个用于创建 GRIB2 消息的样例文件 cma.grib2。
在 2023 年发布的最新版本 V10.0 中，grib-util 首次摆脱对 GRIB-API 的替代，形成了具有完全自主知识产权的模式产品编解码库。
新版本内置了 JPEG2000 编解码库，也不再依赖 GRIB-API 需要的样例文件和定义文件，更方便使用。
目前，新版 grib-util 已全面应用到新一代超算上部署的业务系统中，并随着超算平台切换而实现业务应用。&lt;/p&gt;
&lt;p&gt;GRIB / GRIB2 编解码是气象数据编码的热门领域，诞生了众多的研发成果。&lt;/p&gt;
&lt;p&gt;笔者了解到的 GRIB/GRIB2 开源库有三种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ECMWF 的 ecCodes / GRIB_API&lt;/li&gt;
&lt;li&gt;NOAA-EMC 的 wgrib2 / g2 / g2c / grib_util 等 [1]&lt;/li&gt;
&lt;li&gt;UCAR UNIDATA 的 NetCDF Java 库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CEMC 业务系统中使用 ecCodes、wgrib2、grib_util 提供的命令行工具处理 GRIB2 数据。&lt;/p&gt;</description></item><item><title>视界：earthkit介绍</title><link>https://blog.perillaroc.wang/post/2024/04/2024-04-29-view-introduct-earthkit/</link><pubDate>Mon, 10 Jun 2024 21:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/04/2024-04-29-view-introduct-earthkit/</guid><description>&lt;p&gt;本文翻译自 ECMWF 的一篇通讯文章，介绍 ECMWF 正在开发的 earthkit 工具库。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Introducing earthkit&lt;/p&gt;
&lt;p&gt;by Iain Russell, Tiago Quintino, Baudouin Raoult, Sándor Kertész, Pedro Maciel, James Varndell, Corentin Carton de Wiart, Edward Comyn‑Platt, Olivier Iffrig, James Hawkes, Simon Smart&lt;/p&gt;
&lt;p&gt;in ECMWF Newsletter Number 179 - Spring 2024 (Published in April 2024)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/newsletter/179/computing/introducing-earthkit"&gt;https://www.ecmwf.int/en/newsletter/179/computing/introducing-earthkit&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以下&lt;strong&gt;正文&lt;/strong&gt;部分使用 ChatGPT 和文心一言翻译自原文，并根据笔者理解略有修改。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;Earthkit 是一个由 ECMWF 领导的令人振奋的全新开源 Python 开发项目，通过简化数据访问、处理、分析、可视化等过程，为加速天气和气候科学工作流提供强大的工具。
Earthkit 正处于多年开发的初期阶段，但许多方面已经开放以供测试和反馈。&lt;/p&gt;
&lt;h3 id="earthkit-背景"&gt;Earthkit 背景&lt;/h3&gt;
&lt;p&gt;2023 年，ECMWF 发布了 2023 年至 2027 年的软件战略和路线图 (Quintino et al., 2023)，概述了未来五年软件开发的计划。
支撑软件战略的一些核心原则包括：&lt;/p&gt;</description></item><item><title>连接VPN后无法访问互联网的解决方案</title><link>https://blog.perillaroc.wang/post/2024/06/2024-06-08-use-cma-vpn-and-remote-desk-through-virtual-machine/</link><pubDate>Mon, 10 Jun 2024 13:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/06/2024-06-08-use-cma-vpn-and-remote-desk-through-virtual-machine/</guid><description>&lt;p&gt;笔者从事的远程运维工作严重依赖 VPN 连接到单位内网，再加上工作多年后只剩下了多年工作，而工作又很难脱离内网环境开展，所以笔者是 VPN 的重度使用者。&lt;/p&gt;
&lt;p&gt;本文介绍笔者工作以来使用 VPN 的几种方式，介绍如何在使用 VPN 的同时保持互联网访问。&lt;/p&gt;
&lt;h2 id="方案一"&gt;方案一&lt;/h2&gt;
&lt;p&gt;最简单的方案是在家庭网络的桌面电脑中直接使用 VPN，这也是笔者最早采用的方案。&lt;/p&gt;
&lt;p&gt;该方案有两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;长时间连接 VPN 不安全，容易被黑客利用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;笔者连接 VPN 的电脑曾经被信息部门检查，该次检查促使笔者放弃使用家庭桌面电脑直连 VPN，转而采用双电脑方案。&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;连接 VPN 的电脑无法访问互联网&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;VPN 某次升级后就限制连接 VPN 的电脑访问互联网，甚至连安装的内部 360 软件都无法正常升级。
这也进一步说明双电脑方案的必要性。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/basic/06-08-vpn/desktop-vpn.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 桌面电脑直连 VPN 示意图，开启 VPN 后桌面电脑无法访问互联网&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="方案二"&gt;方案二&lt;/h2&gt;
&lt;p&gt;为了提高使用 VPN 的安全性，笔者在一台专用的笔记本中安装 VPN 环境，桌面电脑通过远程桌面连接笔记本。
该笔记本仅安装连接 VPN 和开展运维工作需要的软件，不安装其他软件，最大程度避免其他软件可能带来的潜在漏洞。
双电脑方案也非常适合将个人家庭用途与工作用途严格分离，做到互不干扰。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/basic/06-08-vpn/desktop-laptop-vpn.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 桌面电脑 + 笔记本连接 VPN 示意图，桌面电脑通过远程桌面访问笔记本，笔记本直接连接 VPN&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;方案二依赖 Windows 自带的远程桌面服务。
最近一次 VPN 更新后，运行 VPN 电脑的远程桌面服务被封掉，桌面电脑无法再通过远程桌面软件连接到笔记本，因此引出了第三种方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：理论上说其他远程桌面连接软件也可以使用，但为了安全起见，不要轻易尝试。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="方案三"&gt;方案三&lt;/h2&gt;
&lt;p&gt;为了解决 VPN 电脑无法使用远程桌面服务的问题，在专用笔记本中启动虚拟机，在虚拟机中安装 VPN 环境，桌面电脑通过远程桌面连接笔记本，笔记本运行虚拟机的可视化桌面。
虚拟机软件使用 Windows 自带的 HyperV，安装 Windows 10 操作系统。
该方案对笔记本性能有一些要求，自从开了虚拟机后，笔者笔记本就时不时传出风扇声，也许将笔记本改为微型台式机更合适一些。&lt;/p&gt;</description></item><item><title>清理数值天气预报业务系统运行目录的几种方法</title><link>https://blog.perillaroc.wang/post/2024/06/2024-06-06-housekeeping-in-nwp-system/</link><pubDate>Fri, 07 Jun 2024 15:34:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/06/2024-06-06-housekeeping-in-nwp-system/</guid><description>&lt;p&gt;数值天气预报模式业务系统每天都在固定时间点启动运行，完成从某个时间点开始的预报，称为一个时次。
比如 CMA-GFS 在北京时间 11:40 启动，开始预报从北京时间 8:00 开始的 10 天预报。
一般按照 UTC 时间将北京时间 8 点的预报称为 00 时次。&lt;/p&gt;
&lt;p&gt;数值预报模式在运行过程中会生成大量中间数据，比如预处理过的观测资料、模式初始场、侧边界条件、参数文件、模式原始输出等。
如果要保证业务系统每天正常滚动运行，就需要对运行目录中的历史数据进行清理，避免不再使用的历史文件占用宝贵的超算高速存储空间。&lt;/p&gt;
&lt;p&gt;目前 CEMC 的数值天气预报业务系统有 3 种组织运行目录的方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单一目录：所有时次均在同一个目录中运行&lt;/li&gt;
&lt;li&gt;按时次划分：为了更方便进行查错，模式预报流程一般按照时次（即小时）来安排运行目录。
比如分成 00、06、12、18 等。&lt;/li&gt;
&lt;li&gt;按起报时间划分：产品制作流程通常只使用当前时次生成的数据，不同时次的产品制作任务能够同时运行，所以可以使用起报时间点来安排运行目录。
比如 2024060512、2024060518、2024060500 等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;清理实时运行目录的复杂性在于不同数据的保留时间不一样。比如模式原始数据文件需要保留几天用于查错，而图片产品则不需要保留太长时间。&lt;/p&gt;
&lt;p&gt;本文介绍不同运行目录组织方式下的常用清理方法。&lt;/p&gt;
&lt;h2 id="单一目录"&gt;单一目录&lt;/h2&gt;
&lt;p&gt;因为每个时次都在同一个目录中运行，所以一般在每个时次运行结束前清理中间数据。
有严重的运维隐患，清理中间数据后无法重复运行依赖这些中间数据的任务，不推荐使用。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：有一种变式是在多个子目录中都保存时次目录，与第二种按时次划分类似&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;有两种常用的清理方法。&lt;/p&gt;
&lt;h3 id="按日期清理"&gt;按日期清理&lt;/h3&gt;
&lt;p&gt;根据过期天数计算得到一个明确的日期，以该日期为关键字查找并删除相关文件。&lt;/p&gt;
&lt;p&gt;下面代码来自 CMA-GEPS 的 houskeeping 任务。其中 &lt;code&gt;$YMD&lt;/code&gt; 是系统运行的当前日期，例如 20240606。&lt;/p&gt;
&lt;p&gt;首先计算得到不同种类数据待删除的日期，与时次字段一起组成起报时间 (&lt;code&gt;DELTIME1&lt;/code&gt;, &lt;code&gt;DELTIME6&lt;/code&gt;)：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLDATE1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;smsdate -D $YMD -3&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DELTIME1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CLDATE1&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;HH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLDATE6&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;smsdate -D $YMD -32&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DELTIME6&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CLDATE6&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;HH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用起报时间删除相关目录和文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;servicesdir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rm -rf &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DELTIME1&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;rundir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/PRODS/TIGGE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rm -rf *&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;DELTIME6&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="按过期时间清理"&gt;按过期时间清理&lt;/h3&gt;
&lt;p&gt;另一种方式利用文件的修改时间进行删除。
业务系统在某个时次运行结束后就不会修改该时次生成的文件，所以文件的修改时间可以作为判断文件是否需要删除的依据。
可以将修改时间超过某个阈值的文件都删掉。&lt;/p&gt;</description></item><item><title>世界读书日荐书《健壮的Python》</title><link>https://blog.perillaroc.wang/post/2024/04/2024-04-23-reading-robust-python/</link><pubDate>Tue, 23 Apr 2024 22:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/04/2024-04-23-reading-robust-python/</guid><description>&lt;p&gt;4 月 23 日是世界读书日。笔者上次写读书笔记还是 2 年前的《&lt;a href="https://blog.perillaroc.wang/post/2022/04/2022-04-10-book-zhi-shen-shi-nei/"&gt;置身事内&lt;/a&gt;》，过去两年时间里没有看完任何一本书。
为了沾点儿读书日的喜庆，笔者推荐正在看的一本编程书《&lt;strong&gt;健壮的 Python&lt;/strong&gt;》(Robust Python)，由美国 Patrick Viafore 著 O`Reilly 出版，中文翻译版由机械工业出版社出版。&lt;/p&gt;
&lt;p&gt;该书不是类似《Python学习手册 (Learning Python)》的 Python 编程入门教程，也不像《Effective Python》那样介绍大量 Python 编程技巧，而是关注“如何编写一段好的代码”，以提高未来的可维护性为目标介绍 Python 编程的一些经验，也就是标题中的“健壮”。
作者在第一章中给出健壮性的定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;尽管一直处在不断变化的环境中，但健壮的代码库是有弹性的和没有缺陷的。&lt;/p&gt;
&lt;p&gt;&amp;ndash; 摘自《健壮的 Python》第一章《健壮的 Python 简介》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;全书共分四个部分，分别是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为代码添加类型注解：代码注释&lt;/li&gt;
&lt;li&gt;定义你自己的类型：类型定义&lt;/li&gt;
&lt;li&gt;可扩展的 Python：代码扩展&lt;/li&gt;
&lt;li&gt;构建安全网：代码质量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前笔者刚看完前两部分。
类型注解部分介绍如何使用 Python 的类型注解功能，从而形成与维护者的明确约定，也方便类型检查工具自动查找代码的缺陷。
类型定义部分则介绍如何为数据结构选择合适的表达方式，向维护者准确表达代码的意图，减少维护者思考的时间，从而降低维护成本。&lt;/p&gt;
&lt;p&gt;增加限制也许会降低未来的维护成本，但必然会带来更多的即时开发成本。
因此该书介绍的经验更适合需要多人长期维护的 Python 项目，而不适合单人开发的 Python 脚本。
简单 Python 脚本的优势在于快速开发，应用书中的方法反而会降低开发速度。&lt;/p&gt;
&lt;p&gt;看完前两章给笔者的感觉是书中介绍的经验都是在试图控制 Python 作为动态类型编程语言的灵活度，从而提高大型 Python 项目的可维护性。
这显然就会引出另外一个问题，是不是 Java、C++、Golang、Rust 等编译型语言更适合开发大型项目。
不过笔者认为 Python 最大的优势在于比较流行，会的人多，尤其是人工智能在科学领域的火爆让越来越多科学家接触 Python 编程，用 Python 开发大型项目更容易形成开发团队。&lt;/p&gt;
&lt;p&gt;最后引用一句 Python 编程领域的名言：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;人生苦短，我用 Python&lt;/p&gt;</description></item><item><title>绘图工具库cedarkit-maps介绍</title><link>https://blog.perillaroc.wang/post/2024/04/2024-04-08-cedarkit-maps-introduction/</link><pubDate>Mon, 08 Apr 2024 22:48:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/04/2024-04-08-cedarkit-maps-introduction/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自笔者 2024 年 3 月 29 日在单位部门内部分享的《cedarkit-maps工具库介绍》。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表笔者个人观点，所选材料截止时间为 2024 年 3 月，不代表当前的业务系统现状。
如果想了解最新信息，请咨询 CEMC 相关部门。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文主要介绍正在开发中的 &lt;a href="https://github.com/cemc-oper/cedarkit-maps"&gt;cedarkit-maps&lt;/a&gt; 绘图工具，包括开发背景、设计、实现与当前开发成果。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;h3 id="业务系统现状"&gt;业务系统现状&lt;/h3&gt;
&lt;p&gt;绘图任务通常分为准备数据和图形绘制两个步骤。当前业务系统在准备数据方面，简单的绘图任务直接使用模式数据，复杂的绘图任务需要计算得到绘图需要的最终数据。比如 CMA-MESO 使用 NCL 脚本实现降水相态计算，CMA-GEPS 使用内部开发的 Fortarn 程序计算概率。在图形绘制方面主要使用 NCL 和 GrADS 绘图，少部分图片产品使用 Python 绘制。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/report/2024-04-cedarkit-maps-intro/cemc-plot-current-by-step.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CEMC业务系统绘图任务现状，按功能划分&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;从工具角度来看，绘图需要使用基础的可视化绘图工具库，例如 NCL、GrADS、Python等。CEMC 使用基础绘图库封装了一系列绘图包，例如 NCL 的 ncllib 和 GrADS 的 map.gs 等脚本，并使用绘图工具库和封装工具库为图片产品开发绘图脚本。同时业务系统的绘图任务需要将业务系统数据与图片产品脚本相关联，通常通过 Shell 脚本调用绘图脚本的方式实现。另外也使用 wgrib2、eccodes 等开源数据处理工具，并为特定的任务开发 Fortran 数据处理程序。绘图脚本中也包含了业务系统的部分信息，比如数据文件命名规范、数据文件路径等。从下图可以看到，业务任务、图片产品、绘图工具库三层之间没有形成明显的边界，导致业务逻辑和绘图实现耦合在一起，影响绘图脚本的适用性。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/report/2024-04-cedarkit-maps-intro/cemc-plot-current-by-tool.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CEMC业务系统绘图任务现状，按工具划分&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="ncl"&gt;NCL&lt;/h4&gt;
&lt;p&gt;NCL 主要用于 CMA-GFS、CMA-MESO，以及 CMA-TYM、CMA-GEPS、CMA-REPS 的部分图形。&lt;/p&gt;
&lt;p&gt;CEMC 基于 NCL 开发了 ncllib 库，提供底图、要素查找、文件路径等功能函数，应用在 GFS 和 MESO 的 大部分 NCL 绘图脚本中。ncllib 内置了 NMIC 发布的中国和世界地图底图 shapefile 数据文件。ncllib 库的典型调用如下所示，代码中加载的 ncllib 脚本说明见下表。&lt;/p&gt;</description></item><item><title>HPC上与其他用户共享conda环境</title><link>https://blog.perillaroc.wang/post/2024/03/2024-03-22-share-conda-env-with-other-users-in-hpc/</link><pubDate>Fri, 22 Mar 2024 09:45:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/03/2024-03-22-share-conda-env-with-other-users-in-hpc/</guid><description>&lt;p&gt;本文以 CMA 新一代超算平台国家级子系统 (以下简称 HPC2023) 为例说明如何在 HPC 上与其他用户共享 conda 环境。&lt;/p&gt;
&lt;p&gt;HPC2023 安装了 conda 软件包 conda/2023.03.01。
下面以 op_post 账户使用 wangdp 账户创建的 py311-data 环境为例说明如何在不同账户之间共享 conda 环境。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 在 wangdp 账户中查看已经创建的 conda 环境&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以下代码在 BShell 中加载并激活 conda 环境：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module load conda/2023.03.01
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eval &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;/g1/app/apps/anaconda/2023.03.01/condabin/conda shell.bash hook&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看已经创建的 conda 环境：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conda env list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;# conda environments:
#
base * /g1/app/apps/anaconda/2023.03.01
py311-cylc /g1/u/wangdp/.conda/envs/py311-cylc
py311-data /g1/u/wangdp/.conda/envs/py311-data
py311-data-oper /g1/u/wangdp/.conda/envs/py311-data-oper
py311-takler /g1/u/wangdp/.conda/envs/py311-takler
py312-ansible /g1/u/wangdp/.conda/envs/py312-ansible
py312-data /g1/u/wangdp/.conda/envs/py312-data
py39-cylc /g1/u/wangdp/.conda/envs/py39-cylc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;默认环境安装在系统目录，用户 (wangdp) 创建的环境放在 &lt;code&gt;/g1/u/wangdp/.conda/envs&lt;/code&gt; 目录中。&lt;/p&gt;</description></item><item><title>视界：Magic可视化的下一步将何去何从？</title><link>https://blog.perillaroc.wang/post/2023/10/2023-10-22-view-what-next-magics-visualisation/</link><pubDate>Fri, 09 Feb 2024 11:45:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/10/2023-10-22-view-what-next-magics-visualisation/</guid><description>&lt;p&gt;本文翻译自 ECMWF 的一篇通讯文章，介绍 ECMWF 开发可视化工具库 Magics/Magics++ 的历史，并介绍 Magics 未来将如何整合进 ECMWF 新的开源项目中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What next for Magics visualisation?&lt;/p&gt;
&lt;p&gt;by Sylvie Lamy-Thépaut, Stephan Siemen, James Varndell&lt;/p&gt;
&lt;p&gt;in ECMWF Newsletter Number 177 - Autumn 2023 (Published in October 2023)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/newsletter/177/computing/what-next-magics-visualisation"&gt;https://www.ecmwf.int/en/newsletter/177/computing/what-next-magics-visualisation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以下正文部分使用 ChatGPT 和文心一言翻译自原文，并根据笔者理解略有修改。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;Magics（Meteorological Applications Graphics Integrated System）是 ECMWF 专门为数据可视化而设计的软件库，自 1985 年首次发布以来，已经发生了重大变化。
本文旨在提供 Magics 的发展历史，并强调 Magics 如何不断适应科学家的需求，特别是在生成高质量天气图、有效处理不断增加的数据分辨率以及采用新标准和技术方面。
文章最后探讨了当前的挑战，并介绍了 Magics 将如何发展成为 ECMWF 雄心勃勃的新开源项目 earthkit 的可视化组件。&lt;/p&gt;
&lt;h3 id="1980s将彩色引入天气图"&gt;1980s：将彩色引入天气图&lt;/h3&gt;
&lt;p&gt;可视化天气预报和观测数据对于理解开发和运行预报模式所涉及的大量数据至关重要。
因此，ECMWF 从一开始就投资建立良好的可视化设施，以使科学家和用户能够处理和开发预报模式并分析其结果：使用预报数据的二维地图和使用其他数据的图形。
在 20 世纪 80 年代，这主要意味着印刷地图，因为计算机屏幕大多分辨率太低，无法显示大型和复杂的地图。
Magics 开发的一个重点是广泛使用颜色，以在地图上叠加不同的参数。&lt;/p&gt;</description></item><item><title>视界：从GRIB1迁移到GRIB2-面向未来准备ECMWF模式输出</title><link>https://blog.perillaroc.wang/post/2023/06/2023-06-20-view-migration-grib1-grib2-preparing-ecmwf-model-output-future/</link><pubDate>Thu, 08 Feb 2024 17:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/06/2023-06-20-view-migration-grib1-grib2-preparing-ecmwf-model-output-future/</guid><description>&lt;p&gt;本文翻译自 ECMWF 在 2023 年 4 月发表的一篇通讯文章，介绍 ECMWF 正在开展的从 GRIB1 迁移到 GRIB2 的相关工作。
这一篇非常好的 GRIB2 数据文件格式入门介绍材料。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Migration from GRIB1 to GRIB2: preparing ECMWF model output for the future
by Robert Osinski Matthew Griffith Sébastien Villaume
in ECMWF Newsletter Number 175 - Spring 2023 (Published in April 2023)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;2022 年，ECMWF 开始一项多年任务，将其日常业务数据输出从文件格式 GRIB 第 1 版 (GRIB1) 迁移到 GRIB 第 2 版 (GRIB2)。
该项目是对 ECMWF 十年战略 2021-2030 中规定的对流尺度分辨率全球数值天气预报 (NWP) 呼吁的响应的一部分。
由于 GRIB1 网格定义的限制，此类分辨率需要 GRIB2 而不是 GRIB1。
几年来，ECMWF 已经使用 GRIB2 格式生成综合预报系统 (Integrated Forecasting System, IFS)的垂直模式层次输出。
本文概述了所有输出从 GRIB1 到 GRIB2 的过渡过程。&lt;/p&gt;</description></item><item><title>2023年工作总结</title><link>https://blog.perillaroc.wang/post/2024/01/2024-01-26-2023-summary-of-working-in-cemc/</link><pubDate>Wed, 31 Jan 2024 11:15:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2024/01/2024-01-26-2023-summary-of-working-in-cemc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自 2023 年 12 月 18 日个人工作汇报做的 PPT。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="系统建设"&gt;系统建设&lt;/h2&gt;
&lt;p&gt;2023 年完成 1 项业务系统升级，建设 CMA-GFS V4.0 后处理业务系统。&lt;/p&gt;
&lt;p&gt;在国家级超算新建 3 套服务保障后处理系统，在杭州、贵州等省局超算新建 4 套产品后处理系统。&lt;/p&gt;
&lt;p&gt;开展国家级新超算 4 套系统迁移工作，正在开展 CMA-GFS 后处理系统等 1 套系统的实时运行测试。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/summary/2023-summary/personal-system.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 2023 年参与建设的系统&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="算法优化"&gt;算法优化&lt;/h3&gt;
&lt;p&gt;在开展系统建设工作的同时，还持续对业务系统的算法和流程进行优化。&lt;/p&gt;
&lt;h4 id="cma-gfs-v40-产品制作任务"&gt;CMA-GFS V4.0 产品制作任务&lt;/h4&gt;
&lt;p&gt;今年将中心青年基金课题项目《基于动态任务调度的数据处理技术》成果应用到 CMA-GFS V4.0 产品制作任务中，对串行任务进行并行化改造。
在 GFS 业务系统中，我们为 NSMC 制作一种 GRIB2 数据产品，需要对基础 GRIB2 数据进行要素筛选和插值。
业务原有串行程序在 V3.3 版本耗时 8 分钟，V4.0 版本因为水平分辨率从 25 KM 提升到 12.5 KM，耗时增长为 20 分钟。
应用课题研究成果后，运行时间从 20 分钟减少为 1 分钟，运行时间减少一个数量级，极大提高产品制作效率。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2024/summary/2023-summary/gfs-prod-algorithm.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 CMA-GFS卫星中心GRIB2产品的并行算法&lt;/em&gt;&lt;/p&gt;</description></item><item><title>论文阅读：ECMWF软件战略和路线图2023-2027</title><link>https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/</link><pubDate>Sun, 17 Dec 2023 12:50:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/08/2023-08-22-paper-ecmwf-software-strategy-and-roadmap-2023-2027/</guid><description>&lt;p&gt;Software Strategy and Roadmap 2023–2027&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tiago Quintino, Umberto Modigliani, Florian Pappenberger, Sylvie Lamy-Thépaut,
Simon Smart, James Hawkes, Iain Russell,
Laurent Gougeon, Cristiano Zanna, Baudouin Raoult,
2023. Software Strategy and Roadmap 2023-2027[R/OL]//Technical Memorandum. ECMWF. DOI:10.21957/c6d7df0322.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/elibrary/81334-software-strategy-and-roadmap-2023-2027"&gt;https://www.ecmwf.int/en/elibrary/81334-software-strategy-and-roadmap-2023-2027&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文是 ECMWF 技术文档 904，发表于 2023 年 1 月。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：以下内容使用 ChatGPT 和文心一言翻译自论文，并根据笔者个人理解有所删改整合。
经笔者试用，ChatGPT 倾向于按照英文原始表述翻译中文，文心一言更倾向于按照中文习惯调整语序，风格迥异，可以结合使用。&lt;/p&gt;
&lt;p&gt;以下名为“&lt;strong&gt;译注&lt;/strong&gt;”的章节均为笔者添加，阐述笔者对某章节的个人理解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="摘要"&gt;摘要&lt;/h2&gt;
&lt;p&gt;ECMWF开发了多个软件包以支持其主要目标，即发展中期天气预报能力，向成员国提供中期天气预报，以及与此目标一致的其他目标。
这一战略支持《&lt;a href="https://www.ecmwf.int/en/about/what-we-do/strategy"&gt;ECMWF Strategy 2021-2030&lt;/a&gt;》，尤其是旨在开发并应用尖端科学和技术的&lt;strong&gt;科学技术&lt;/strong&gt;目标，以及旨在为 ECMWF 成员国提供卓越的性价比的&lt;strong&gt;影响&lt;/strong&gt;目标。
因此，许多软件包也被成员国、合作国以及其他用户用于处理和分析 ECMWF 归档或分发数据。
这些软件包经过多年甚至几十年的开发，持续为 ECMWF 业务提供可靠服务。&lt;/p&gt;
&lt;p&gt;作为我们不断追求效率和改进的一部分，ECMWF 正在审查其软件包的战略和路线图。
支撑 ECMWF 软件战略的一般原则如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;高效使用开发资源&lt;/strong&gt; (Efficeint use of development resources)。
我们的目标是在现有的开发资源基础上，继续支持当前服务，并在广度和深度上提供持续增长的能力。
为了实现这一目标，我们需要合理化和高效化所有开发活动，并尽量减少软件维护工作。
这将通过现代化、降低技术债务以及整合功能来实现，从而降低维护成本。&lt;/p&gt;</description></item><item><title>date命令格式化输出日期字符串</title><link>https://blog.perillaroc.wang/post/2023/10/2023-10-13-format-date-using-data-command/</link><pubDate>Fri, 13 Oct 2023 23:39:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/10/2023-10-13-format-date-using-data-command/</guid><description>&lt;p&gt;本文介绍如何使用 Linux 的 &lt;code&gt;date&lt;/code&gt; 命令对日期字符串进行格式化输出。&lt;/p&gt;
&lt;h2 id="date-命令简介"&gt;date 命令简介&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;date&lt;/code&gt; 命令默认打印系统当前时间。
例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Fri Oct 13 22:14:50 CST 2023
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;date&lt;/code&gt; 命令支持对输出字符串进行格式化，通过 &lt;code&gt;+&amp;quot;格式化字符串&amp;quot;&lt;/code&gt; 实现，类似 Python 中 &lt;code&gt;datetime.datetime.strftime&lt;/code&gt; 函数。
例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date +&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-%d %H:%M:%S&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;2023-10-13 22:18:59
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;还可以通过 &lt;code&gt;--date&lt;/code&gt; 参数指定具体的时间，而不是用系统当前时间，类似 Python 中 &lt;code&gt;datetime.datetime.strptime&lt;/code&gt;。
例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date --date &lt;span style="color:#e6db74"&gt;&amp;#34;2023-10-03 12:00&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Tue Oct 3 12:00:00 CST 2023
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;--date&lt;/code&gt; 和 &lt;code&gt;+&lt;/code&gt; 可以同时使用，用于格式化输出日期字符串。
例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date --date &lt;span style="color:#e6db74"&gt;&amp;#34;2023/10/03 12:00&amp;#34;&lt;/span&gt; +&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-%d %H:%M:%S&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;2023-10-03 12:00:00
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下面用一个实际的例子说明具体用法。&lt;/p&gt;
&lt;h2 id="应用"&gt;应用&lt;/h2&gt;
&lt;p&gt;数值天气预报模式 Fotran 程序输出的二进制文件通常会附带一个 CTL 文件用于描述文件内容，可以被 GrADS、NCL 等绘图工具识别。&lt;/p&gt;
&lt;p&gt;下面是杭州亚运会 CMA-MESO 1KM 模式输出 postvar 文件的 CTL 文件样例（部分内容省略）：&lt;/p&gt;</description></item><item><title>ecCodes学习笔记：如何关掉ecCodes的常量场特性</title><link>https://blog.perillaroc.wang/post/2023/05/2023-05-31-how-to-close-constant-field-in-eccodes/</link><pubDate>Mon, 05 Jun 2023 22:12:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/05/2023-05-31-how-to-close-constant-field-in-eccodes/</guid><description>&lt;h2 id="简述"&gt;简述&lt;/h2&gt;
&lt;p&gt;设置环境变量 &lt;code&gt;ECCODES_GRIB_LARGE_CONSTANT_FIELDS&lt;/code&gt; 可以关掉 ecCodes 的常量场 (constant field) 特性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ECCODES_GRIB_LARGE_CONSTANT_FIELDS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;CMA-GFS 提供 GRIB2 全球预报产品 (grib2-orig)，为了降低数据传输量，从全球预报产品中抽取四分之一区域生成 GRIB2 东北半球产品 (grib2-ne)。
在 CMA-GFS V4.0 升级前 grib2-ne 使用 CEMC 内部开发的 grib_post.exe 制作，但 V4.0 分辨率从 25 KM 升到 12.5 KM，串行程序运行速度显著变慢。
为了提高产品生成速度，实现了 python + dask + eccodes 的并行抽取版本，将产品制作时间从十多分钟降低为两分钟，详情见参考文章4。
但使用 wgrib2 工具读取新算法生成的 grib2-ne 数据会出现警告信息，笔者检查数据发现有告警信息的要素场都是常量场。
经过上网搜索发现问题出在 wgrib2 不支持常量编码方式，通过查看 ecCodes 源码最终发现通过设置环境变量 &lt;code&gt;ECCODES_GRIB_LARGE_CONSTANT_FIELDS&lt;/code&gt; 可以关掉 ecCodes 的常量场特性。&lt;/p&gt;
&lt;p&gt;本文首先介绍什么是常量场，并给出 CMA-GFS 常量场示例，然后介绍 wgrib2 和 g2ctl.pl 告警信息，并说明告警实际上不影响对数据的使用，最后通过分析源码介绍如何关掉 ecCodes 的常量场特性。&lt;/p&gt;
&lt;h3 id="什么是常量场"&gt;什么是常量场&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;常量场&lt;/strong&gt; (constant field) 是所有数据点值都相同的要素场。&lt;/p&gt;</description></item><item><title>GOLANG交叉编译：从AMD64到ARM64</title><link>https://blog.perillaroc.wang/post/2023/04/2023-04-25-golang-crossbuild-arm64-on-amd64/</link><pubDate>Sun, 07 May 2023 20:25:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/04/2023-04-25-golang-crossbuild-arm64-on-amd64/</guid><description>&lt;p&gt;GO 语言可以方便地实现跨平台交叉编译。&lt;/p&gt;
&lt;p&gt;以在 amd64 平台上为 arm64 平台编译可执行程序为例进行说明。
amd64 平台使用 intel CPU，RedHat 操作系统。arm64 使用华为鲲鹏 CPU，CentOS 操作系统。&lt;/p&gt;
&lt;p&gt;在执行编译命令前设置目标平台的环境变量。
因为 GO 交叉编译不支持 CGO，所以需要关掉 CGO。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;linux GOARCH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;arm64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CGO_ENABLES&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后执行编译命令即可得到目标平台 arm64 的可执行程序。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;最近在 Hangzhou2022 项目中将 CMA-MESO 1KM 后处理系统从 CMA-PI HPC 到迁移到项目 HPC 上。
两个平台都使用 Linux 操作系统，但 CPU 架构不同。
CMA-PI 是 Intel 芯片，X86-64 架构，而项目 HPC 采用 Huawei 芯片，是 ARM64 架构。
对于使用 ecFlow 构建的业务系统流程来说，定义系统流程的 Python 脚本、完成具体任务的 SHELL 脚本都具有很强的跨平台迁移能力，无需太多改动。
但数值模式业务系统中除了数值模式本身的程序之外，还有很多支持程序，主要集中在前处理和后处理两部分。
在跨平台移植模式系统时，这类程序同样也需要进行迁移。&lt;/p&gt;
&lt;p&gt;CMA-MESO 1KM 后处理系统中使用了笔者开发的数据文件检查工具 &lt;a href="https://github.com/cemc-oper/nwpc-data-client"&gt;cemc-oper/nwpc-data-client&lt;/a&gt;。
该工具支持在多个目录中查找业务系统数据文件，是将各自独立运行的模式系统与后处理系统紧密相连的关键组件。
该工具使用GOLANG实现，在 CMA-PI HPC 上编译成可执行程序，应用在多个产品后处理系统中。
编译过程中，通过在工作电脑架设代理的方式，将依赖库下载到 HPC 上。&lt;/p&gt;</description></item><item><title>使用wgrib2实现GRIB2文件要素场抽取</title><link>https://blog.perillaroc.wang/post/2023/04/2023-04-23-grib-notebook-extract-field-using-wgrib2/</link><pubDate>Mon, 24 Apr 2023 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/04/2023-04-23-grib-notebook-extract-field-using-wgrib2/</guid><description>&lt;p&gt;本文介绍如何使用 &lt;code&gt;wgrib2&lt;/code&gt; 和 &lt;code&gt;grep&lt;/code&gt; 从 GRIB2 文件中抽取指定要素场生成新的 GRIB2 文件。&lt;/p&gt;
&lt;p&gt;wgrib2 是美国 NCEP 开发的 GRIB2 格式文件处理工具。&lt;/p&gt;
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;CEMC 正在建立 CMA-MESO 1KM 逐小时循环预报系统，并面向 2021chengdu 开发预报产品。
因为逐小时循环系统一天运行 24 次，所以一个预报时次的所有产品需要在一个小时内完成传输。
前期已生成一套 GRIB2 产品（grib2-orig），每个文件 340 MB，一个时次 28 个文件一共 9.5 GB。
假设下载带宽为 3MB/s，那么下载一个时次全部数据需要 56 分钟，对于每个小时都运行的系统来说基本没有容错空间。
考虑到网络传输带宽有限，需要对数据进行精简，提供尽可能少的要素场，减少单个数据文件的大小。
这就需要从已有 GRIB2 产品文件中抽取指定要素场生成新的 GRIB2 产品文件（grib2-bccd）。&lt;/p&gt;
&lt;p&gt;grib2-orig 产品示例 rmf.hgra.2023042300006.grb2 文件的 wgrib2 输出如下所示，每行代表一个要素场，一共 256 个要素场。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1:0:d=2023042300:APCP:surface:0-6 hour acc fcst:
2:2462709:d=2023042300:TMP:surface:6 hour fcst:
3:4321648:d=2023042300:HGT:surface:6 hour fcst:
4:6400691:d=2023042300:SPFH:2 m above ground:6 hour fcst:
5:7338630:d=2023042300:TMP:2 m above ground:6 hour fcst:
...
251:358186619:d=2023042300:var discipline=0 center=38 local_table=1 parmcat=7 parm=225:surface:6 hour fcst:
252:358387277:d=2023042300:PWAT:entire atmosphere:6 hour fcst:
253:360263004:d=2023042300:VIS:surface:6 hour fcst:
254:361389756:d=2023042300:GUST:10 m above ground:6 hour fcst:
255:363531777:d=2023042300:CDCTOP:surface:6 hour fcst:
256:365300689:d=2023042300:CDCB:surface:6 hour fcst:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根据要素表格对数据进行抽取，要素表格如下所示：&lt;/p&gt;</description></item><item><title>conda中使用ecCodes不支持JPEG解码的问题查错</title><link>https://blog.perillaroc.wang/post/2023/04/2023-04-21-eccodes-in-anaconda-not-support-jpeg/</link><pubDate>Fri, 21 Apr 2023 22:12:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/04/2023-04-21-eccodes-in-anaconda-not-support-jpeg/</guid><description>&lt;p&gt;本文是对笔者近期遇到的一次 Python + ecCodes 解码出错问题的总结。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;最近在 CMADaaS 容器中测试处理 GRIB2 数据的 Python 脚本，使用 CMA 镜像安装 Anaconda 环境和软件包，运行后报错，提示 ecCodes 不支持 JPEG 解码。
报错信息如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-pycon" data-lang="pycon"&gt;&amp;gt;&amp;gt;&amp;gt; import eccodes
&amp;gt;&amp;gt;&amp;gt; f = open(&amp;#34;Z_NAFP_C_BABJ_20230409180000_P_NWPC-GRAPES-GFS-HNEHE-12000.grib2&amp;#34;, &amp;#34;rb&amp;#34;)
&amp;gt;&amp;gt;&amp;gt; m = eccodes.codes_grib_new_from_file(f)
&amp;gt;&amp;gt;&amp;gt; eccodes.codes_get_double_array(m, &amp;#34;values&amp;#34;)
ECCODES ERROR : JPEG support not enabled.
Traceback (most recent call last):
 File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
 File &amp;#34;/space/cmadaas/dpl/CEMC_OPER_PROD/anaconda3/envs/py311-plot/lib/python3.11/site-packages/gribapi/gribapi.py&amp;#34;, line 1196, in grib_get_double_array
 GRIB_CHECK(err)
 File &amp;#34;/space/cmadaas/dpl/CEMC_OPER_PROD/anaconda3/envs/py311-plot/lib/python3.11/site-packages/gribapi/gribapi.py&amp;#34;, line 230, in GRIB_CHECK
 errors.raise_grib_error(errid)
 File &amp;#34;/space/cmadaas/dpl/CEMC_OPER_PROD/anaconda3/envs/py311-plot/lib/python3.11/site-packages/gribapi/errors.py&amp;#34;, line 382, in raise_grib_error
 raise ERROR_MAP[errid](errid)
gribapi.errors.FunctionalityNotEnabledError: Functionality not enabled
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="原因"&gt;原因&lt;/h2&gt;
&lt;p&gt;报错原因是在该容器在 &lt;code&gt;/usr/local&lt;/code&gt; 目录下安装了没有启用JPEG支持的 eccodes 库。&lt;/p&gt;</description></item><item><title>在HPC不同账户之间迁移conda环境</title><link>https://blog.perillaroc.wang/post/2023/03/2023-03-01-move-conda-env-between-different-users-in-hpc/</link><pubDate>Thu, 02 Mar 2023 21:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2023/03/2023-03-01-move-conda-env-between-different-users-in-hpc/</guid><description>&lt;p&gt;本文介绍在 HPC 上如何使用 conda-pack 工具将 conda 环境从一个账户迁移到另一个账户。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;HPC 上有业务账户和个人科研账户。对于科研账户，用户可以自行尝试各种软件，比如我在个人账户中安装了 Anaconda，通过各种方式安装了大量第三方包。
但对于业务账户，为了保证业务系统稳定运行，不能随意安装软件，以免破坏运行环境。&lt;/p&gt;
&lt;p&gt;如果在业务系统中使用 Python 脚本，并且该脚本使用到了系统 Python 环境中没有的库，就会带来应用部署问题。
需要找到一种适合在业务账户中安装自定义 Python 环境的方法。&lt;/p&gt;
&lt;p&gt;一种方案是将 Python 脚本通过工具打包为可执行程序，例如使用 Pyinstaller 包。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优势：一次编译到处运行，不依赖开发账户的 Python 环境&lt;/li&gt;
&lt;li&gt;劣势：修改脚本需要重新编译&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另一种方案是在业务系统中部署 Python 环境，比如使用同样的系统安装的 Python 包，在 Python 环境中运行 Python 脚本。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优势：可以在业务环境中直接修改、调试 Python，无需进行额外编译&lt;/li&gt;
&lt;li&gt;劣势：需要在业务账户中部署 Python 环境。如果 Python 环境是用户自己安装的，则需要迁移到业务环境中，因为业务系统严禁依赖个人账户下的任务文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文针对第二种方案，使用 conda-pack 工具将个人账户的 conda 环境迁移到业务账户。&lt;/p&gt;
&lt;p&gt;以下代码均在 CMA-PI 超算上运行。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;已预先创建一个 Conda 环境 py311-data：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;. /g1/u/wangdp/start_anaconda3.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conda activate py311-data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;which python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;/g11/wangdp/lang/python/anaconda3/envs/py311-data/bin/python3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;安装 conda-pack 包。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：可以在 base 环境中安装&lt;/p&gt;</description></item><item><title>2022年第三季度工作总结</title><link>https://blog.perillaroc.wang/post/2022/10/2022-10-08-2022-q3-summary/</link><pubDate>Mon, 07 Nov 2022 16:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/10/2022-10-08-2022-q3-summary/</guid><description>&lt;h2 id="计划完成情况"&gt;计划完成情况&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;核心任务&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工作流
&lt;ul&gt;
&lt;li&gt;✔️ 目标：连续一周运行 CMA-GFS 后处理&lt;/li&gt;
&lt;li&gt;✔️ 开发：开发时间依赖&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;主要任务&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模式产品消息库
&lt;ul&gt;
&lt;li&gt;✔️ 消息：已接收 CMADaaS 消息，完成消息工具开发&lt;/li&gt;
&lt;li&gt;✔️ 消息库：已建立基于 redis 的产品消息库&lt;/li&gt;
&lt;li&gt;🚧 应用：通过 redis 产品库对接加工流水线算法&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;绘图调度工具 ploto
&lt;ul&gt;
&lt;li&gt;✔️ 绘图：已集成 sokort 绘图&lt;/li&gt;
&lt;li&gt;✔️ 数据：通过挂载目录对接 CMADaas 模式数据集&lt;/li&gt;
&lt;li&gt;❌ 应用：尚未找到适合云平台的产品后处理任务运行集成技术方案&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;分布式调度技术
&lt;ul&gt;
&lt;li&gt;❌ 试验：分析批量试验数据，开展更多试验&lt;/li&gt;
&lt;li&gt;❌ 总结：将已测试结果整理为技术文档&lt;/li&gt;
&lt;li&gt;❌ 应用：寻找其他应用场景（较难）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;工具开发&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reki
&lt;ul&gt;
&lt;li&gt;❌ 测试：开发多环境测试代码 (CMA-PI，Linux，Cloud)&lt;/li&gt;
&lt;li&gt;❌ 文档：完善文档，为已开发功能撰写用户文档&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;nuwe-cmaddas-python
&lt;ul&gt;
&lt;li&gt;❌ 文档：完善文档，为已开发功能撰写用户文档&lt;/li&gt;
&lt;li&gt;❌ 开发：仿照业务检索程序开发新功能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;meda
&lt;ul&gt;
&lt;li&gt;❌ 调研：调研业界主流 Python 气象绘图包，撰写调研报告&lt;/li&gt;
&lt;li&gt;❌ 开发：继续仿制业务图形，争取确定 API 接口风格&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;mofis
&lt;ul&gt;
&lt;li&gt;❌ 随意发挥&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="业务系统"&gt;业务系统&lt;/h3&gt;
&lt;h4 id="cma-gfs-v33-后处理升级切换"&gt;CMA-GFS V3.3 后处理升级切换&lt;/h4&gt;
&lt;p&gt;CMA-GFS V3.3 的后处理系统已在第二季度完成开发，原定于 9 月 14 日进行切换，因为当时有台风，为保证预报性能稳定，推迟到 9 月 21 日正式切换。&lt;/p&gt;</description></item><item><title>关于未来工作方向的一些思考</title><link>https://blog.perillaroc.wang/post/2022/09/2022-09-29-thoughts-future-direction-about-department/</link><pubDate>Thu, 29 Sep 2022 18:28:22 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/09/2022-09-29-thoughts-future-direction-about-department/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是在中心成立一周年之际，在处室内部科级工作讨论会上的发言，介绍本年度前三季度工作及对未来工作方向的思考。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="个人"&gt;个人&lt;/h3&gt;
&lt;p&gt;今年主要开展两方面的工作：&lt;/p&gt;
&lt;p&gt;第一方面工作以产品制作流程为主线，包括信息化工程和部分开发工作，目前已开展的工作包括建立产品消息库，绘图算法封装，但进展比较缓慢。
最终目标是构建一个独立的产品制作系统，将目前基于本地文件使用 NCL 的绘图任务改为基于数据 API 接口使用 Python 实现绘图。
未来还需要开发模式要素库、模式产品库、绘图工具包等工作，需要科里和室里同事共同完成。&lt;/p&gt;
&lt;p&gt;二是仿照 ecFlow 开发工作流调度工具，也是今年花费时间最多的工作。
ecFlow 是非常成熟的开源工具，也满足我们中心的业务需求。
但我还是觉得我们应该自己开发一些工具，尤其是流程调度这类业务系统中比较关键的工具。
程序员擅长重复造轮子，互联网大厂有许多面向 KPI 编程的开源项目，我们可以借鉴过来，构建中心自己的开源项目。&lt;/p&gt;
&lt;h3 id="科"&gt;科&lt;/h3&gt;
&lt;p&gt;科里和室里发展的大方向在之前多次的讨论中已基本凝练为四个方向，即&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据平台&lt;/li&gt;
&lt;li&gt;产品平台&lt;/li&gt;
&lt;li&gt;运维平台&lt;/li&gt;
&lt;li&gt;中试平台&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;某种程度上说想法和创意并不值钱，我们可以摸着欧洲中心过河，真正有价值的是能够落地的创意。&lt;/p&gt;
&lt;p&gt;从我自己来说，我觉得自底向上比自顶向下更容易实现，所以我认为我们需要在总体目标的指导下开发一系列小工具，使用这些小工具，将这些小工具组成一个大的平台。
在工具开发和工具组织过程中，我们可以寻找一种合适的内部合作方式。
比如可以开发工具中的某个小组件，如果不想开发源代码，可以对工具进行测试，编写文档等等工作。
甚至如果愿意，可以将这些工具做成开源项目，向外输出我们的工作成果。
这也符合中心的发展战略，让更多的力量参与到数值预报业务系统建设中。&lt;/p&gt;
&lt;h3 id="处室"&gt;处室&lt;/h3&gt;
&lt;p&gt;对于处室的发展战略，我还有一条建议。
我们现在的业务运行系统是纵向布局的，即按模式系统区分，甚至有时对外仅说成一个数值预报业务系统。
这样会将系统科的工作淹没在模式研发工作中，我们也做了大量的工作，但没法体现在成果中。
我建议从纵向布局改为横向整合，我们独立于各个模式将业务系统的共性步骤进行整合，形成一个一个有关联的系统。
比如资料检索、资料同化、模式积分、产品制作、产品分发、数据归档等等，这样更容易体现我们的工作。
当然&lt;strong&gt;我的理解不一定正确&lt;/strong&gt;，大家感兴趣可以找时间讨论讨论。&lt;/p&gt;
&lt;p&gt;另外，对于中心正在推广的协同研发机制，我也想谈一下自己的想法。
就我观察目前中心有三种技术开发模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;别人有现成的技术，我们买过来引进到中心&lt;/li&gt;
&lt;li&gt;我们自己有想法点子，通过经费找人来将想法实现&lt;/li&gt;
&lt;li&gt;我们自己有技术实现，想通过合作对技术进行包装从而最终落地部署&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;虽然只要最终的目标都是能在中心应用，但对成果和知识产权的认定还有很多地方尚未明确。
合作需要明确我们自己在其中扮演的角色，每个人都应该可以选择更适合自己的工作方式。&lt;/p&gt;
&lt;p&gt;我个人更倾向于第3种模式，我们必须拥有自己的核心技术，才能在合作中占据主导地位。
这种核心技术一定是中心业务研发工作中确实需要的，可以持续长远发展的。当然哪些才是核心技术其实是随着发展阶段不同而不断变化的，所以这种选择具有押宝的成分。
即使是引进的技术，也要走引进消化吸收再创新的道路，避免重现当年国内引进汽车时“市场换技术”的失败策略。
我们一定培养各项技术的核心骨干，要培养中心自己的人才梯队。
过度依赖外部开发团队会因外部团队人事变动而让这项技术变得非常脆弱。
很少有核心技术是能通过看技术文档短期掌握的，都需要核心成员的传帮带。&lt;/p&gt;
&lt;h2 id="后记"&gt;后记&lt;/h2&gt;
&lt;p&gt;个人发展与单位发展难免会存在一定的冲突，尤其是有上级管理部门的单位，个人发展还会存在与全局统筹规划之间的冲突。
如何寻找个人、单位、大局之间的利益平衡点，是非常值得深入思考的事情。
不能简单地“服从组织安排,听从领导指挥”而放弃自我思考，要结合自身实际情况，在符合总体规划布局框架下，寻找适合自己的工作路线。
对于超过三十年的整个职业生涯来说，五年规划占六分之一，五年时间说短当然不合适，要说长也没有显得那么长。
说不定下个或下下个五年规划会带来全新的变化，所以我认为一定要选择哪些可长远持续发展的工作方向，不要被外部条件制约自己的职业规划。&lt;/p&gt;
&lt;p&gt;2023.03 注：去年第四季度什么事情都没有做，本来想写一些对参考链接会议的感想，现在已经想不起来了，就不再补充了。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;CMA 微信公众号：《&lt;a href="https://mp.weixin.qq.com/s/nJc5VQM1U1KH-vINOexqHw"&gt;第二次全国气象信息化工作会议强调 着力推动信息化发展方式转型升级&lt;/a&gt;》&lt;/p&gt;</description></item><item><title>使用pytest为datetime.now函数设置固定时间</title><link>https://blog.perillaroc.wang/post/2022/09/2022-09-20-mock-datetime-now-using-pytest/</link><pubDate>Tue, 20 Sep 2022 15:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/09/2022-09-20-mock-datetime-now-using-pytest/</guid><description>&lt;p&gt;如果函数中使用当前时间，想要使用固定的输入开展测试就需要使用某种方法伪造一个固定时间。
Pytest 提供 monkeypatch 功能支持修改某个对象的属性。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 pytest 让 Python 内置库函数 &lt;code&gt;datetime.datetime.now()&lt;/code&gt; 返回某个固定的时间点。&lt;/p&gt;
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;近期仿照 ecFlow 项目为 &lt;a href="https://github.com/perillaroc/takler"&gt;takler&lt;/a&gt; 项目开发时间依赖功能 (&lt;code&gt;TimeAttribute&lt;/code&gt;)。
如果某节点设置了时间依赖关系，那么该节点所包含的任务节点只有在指定时刻才会触发运行。&lt;/p&gt;
&lt;p&gt;每个工作流都有一个日历属性 (&lt;code&gt;Calendar&lt;/code&gt;)，保存工作流运行的起始时间 (&lt;code&gt;initial_time&lt;/code&gt;) 和工作流的当前时间 (&lt;code&gt;flow_time&lt;/code&gt;)，该属性由工作流之外的定时任务来更新。
在工作流开始运行时，系统会调用 &lt;code&gt;Calendar.begin()&lt;/code&gt; 函数初始化日历属性，该函数使用 &lt;code&gt;datetime.datetime.now()&lt;/code&gt; 函数记录工作流启动时的机器时间 &lt;code&gt;initial_real_time&lt;/code&gt;。
后续更新日历时间时，会使用该属性计算工作流的当前时间 &lt;code&gt;flow_time&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Calendar&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;begin&lt;/span&gt;(self, time: datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;initial_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;flow_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;duration &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;timedelta()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;increment &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;timedelta()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;initial_real_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;now()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;last_real_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;initial_real_time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在测试时，为了得到明确的结果，一般使用确定的输入值传递给测试函数，比如指定一个固定的时间。
&lt;code&gt;initial_real_time&lt;/code&gt; 时间取自测试运行时的机器时间，如果测试时间与实际运行的机器时间差别较大，就会产生问题，导致测试失败。
（因为工作流时间通过计算得到，考虑了起始时间与起始机器时间的差值）。
所以需要让 &lt;code&gt;datetime.datetime.now()&lt;/code&gt; 返回一个固定的时间，才能完成理想的测试流程。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;使用 pytest 的 fixture 和 monkeypatch 功能，从 &lt;code&gt;datetime.datetime&lt;/code&gt; 派生一个新类，让 &lt;code&gt;now()&lt;/code&gt; 方法返回固定的时间：&lt;/p&gt;</description></item><item><title>ecFlow实战教程：构建CMA-TYM模式的简化版流程</title><link>https://blog.perillaroc.wang/post/2022/07/2022-07-27-ecflow-in-action-build-a-simple-cma-tym-workflow/</link><pubDate>Wed, 27 Jul 2022 21:16:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/07/2022-07-27-ecflow-in-action-build-a-simple-cma-tym-workflow/</guid><description>&lt;p&gt;本文介绍的 ecFlow 实战教程是为 CEMC 2022 新员工培训课程 ecFlow 上机实习环节撰写的上机操作手册，以简化版 CMA-TYM 为例说明如何使用 ecFlow 在 CMA-PI HPC 上搭建并运行数值预报模式流程。
因本轮培训已安排 ecFlow 介绍，因此本教程不介绍 ecFlow 的基本概念和使用方法，仅从实战角度出发介绍如何搭建真实的模式运行流程。&lt;/p&gt;
&lt;p&gt;这是我第一次在新职工培训中介绍 ecFlow 软件，尝试抛弃 ecFlow 教程中常见的使用模拟简单工作流的形式，通过搭建可以实际运行的数值预报模式流程来介绍 ecFlow 的使用方法。
我认为搭建并运行一个有实际意义的示例比单纯介绍 ecFlow 基本用法更有吸引力。
我的核心目标是告诉新同事使用 ecFlow 搭建数值预报系统其实并不复杂，但准备时间比较仓促，加上讲授经验不足，导致上机实习的效果不太理想。
如果未来还有机会参与培训，我还是会继续尝试介绍如何搭建真实的工作流。&lt;/p&gt;
&lt;p&gt;ecFlow 上机实战教程是 Github 上的开源项目，使用 Sphinx 编写，并发布在 readthedocs 网站，欢迎感兴趣的朋友访问。&lt;/p&gt;
&lt;p&gt;实战教程源码：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/perillaroc/cemc-ecflow-tutorial-2022"&gt;https://github.com/perillaroc/cemc-ecflow-tutorial-2022&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在线访问，可以下载 PDF 格式文档：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cemc-ecflow-tutorial-2022.readthedocs.io"&gt;https://cemc-ecflow-tutorial-2022.readthedocs.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;简化版 CMA-TYM 流程的 ecFlowUI 截图：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/tutorial/cemc-ecflow-tutorial-2022/ecflow-tutorial-cma-tym.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;运行完成的简化版 CMA-TYM 流程&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;ECMWF 官方 ecFlow 教程（介绍最新的 v5 版本）：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://confluence.ecmwf.int/display/ECFLOW/Tutorial"&gt;https://confluence.ecmwf.int/display/ECFLOW/Tutorial&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我之前翻译的 ecFlow 中文版教程（仅介绍 v4 版本）：&lt;/p&gt;</description></item><item><title>2022年第二季度工作总结</title><link>https://blog.perillaroc.wang/post/2022/07/2022-07-01-2022-q2-summary/</link><pubDate>Fri, 22 Jul 2022 22:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/07/2022-07-01-2022-q2-summary/</guid><description>&lt;p&gt;最近天气比较热，二季度工作总结拖了 22 天才写完，第三季度已经快过去四分之一，必须尽快将总结这项必须任务完结，好开启下一个阶段。&lt;/p&gt;
&lt;p&gt;我在一季度末决定减少涉猎的工作项目，专注于工作流工具开发。
现在虽然还看不到这个决定是否正确，但有一点可以肯定，这三个月中我纠结应该做哪项工作频率明显降低，工作流工具开发也有了明显的进展。
当然，开发一个自娱自乐的项目对工作来说没有任何价值，接下来我应该继续坚持专注一个领域，把工作做深做实，争取开发出有实用的工具。&lt;/p&gt;
&lt;h2 id="计划完成情况"&gt;计划完成情况&lt;/h2&gt;
&lt;p&gt;第二季度工作只做了&lt;strong&gt;一项&lt;/strong&gt;工作，即工作流工具开发，计划完成情况如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工作流
&lt;ul&gt;
&lt;li&gt;✔️ 模式积分流程：已实现 CMA-TYM 模式流程和 CMA-GFS 部分后处理流程&lt;/li&gt;
&lt;li&gt;🚧 功能开发：正在进行中&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;模式要素库
&lt;ul&gt;
&lt;li&gt;❌ 调研 FDB 库&lt;/li&gt;
&lt;li&gt;🚧 团队讨论：已进行一次，尚需更多讨论&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;分布式调度
&lt;ul&gt;
&lt;li&gt;❌ 分析第一季度试验结果&lt;/li&gt;
&lt;li&gt;❌ 技术报告&lt;/li&gt;
&lt;li&gt;❌ 应用：因活动推迟，保障系统尚未建立&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;运维技术
&lt;ul&gt;
&lt;li&gt;✔️ 产品消息：已测试 CMADaaS 消息&lt;/li&gt;
&lt;li&gt;❌ Redis 产品消息库&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;reki
&lt;ul&gt;
&lt;li&gt;❌文档和测试用例&lt;/li&gt;
&lt;li&gt;❌ 推广&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;sokort
&lt;ul&gt;
&lt;li&gt;❌ PI 预安装环境&lt;/li&gt;
&lt;li&gt;❌ 更新 JupyterHub 环境&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;meda：
&lt;ul&gt;
&lt;li&gt;❌ 调研&lt;/li&gt;
&lt;li&gt;❌ 开发&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;❌ mofis：未开展&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="业务系统"&gt;业务系统&lt;/h3&gt;
&lt;h4 id="cma-gfs-v33-后处理"&gt;CMA-GFS V3.3 后处理&lt;/h4&gt;
&lt;p&gt;新版 CMA-GFS V3.3 业务系统将使用 CMA-PI 上的 SSD 分区，后处理系统也同样调整到 /g0 分区下运行。
第二季度构建了 V3.3 版的后处理系统，通过业务化测试。
因为平行试验效果问题，原定于 6 月底升级切换延后到第三季度。&lt;/p&gt;</description></item><item><title>如何使用Pytest跳过部分测试用例</title><link>https://blog.perillaroc.wang/post/2022/06/2022-06-14-pytest-skip-on-windwos/</link><pubDate>Wed, 15 Jun 2022 14:54:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/06/2022-06-14-pytest-skip-on-windwos/</guid><description>&lt;p&gt;面向跨平台开发的工具库会有部分代码与操作系统相关，比如 Linux 中使用 Shell 脚本，而在 Windows 中则使用 Powershell 脚本。
为 Shell 脚本功能编写的单元测试无需在 Windows 环境中运行，因此就需要根据操作系统自动跳过某些测试。&lt;/p&gt;
&lt;p&gt;本文介绍如何在 Pytest 中跳过指定的测试用例。&lt;/p&gt;
&lt;h2 id="测试文件"&gt;测试文件&lt;/h2&gt;
&lt;p&gt;在目录 test_all 中创建两个简单的测试文件：&lt;/p&gt;
&lt;p&gt;test_bar.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_bar_one&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_bar_two&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;test_foo.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_foo_one&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_foo_two&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行目录 test_all 下的所有测试，测试结果如下&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;============================= test session starts =============================
collecting ... collected 4 items

test_bar.py::test_bar_one PASSED [ 25%]
test_bar.py::test_bar_two PASSED [ 50%]
test_foo.py::test_foo_one PASSED [ 75%]
test_foo.py::test_foo_two PASSED [100%]

============================== 4 passed in 0.03s ==============================
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="跳过测试"&gt;跳过测试&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pytest.mark.skip&lt;/code&gt; 用于跳过测试。&lt;/p&gt;</description></item><item><title>视界：ECMWF模式IFS开源部分组件</title><link>https://blog.perillaroc.wang/post/2022/06/2022-06-11-view-making-some-of-the-ifs-open-source/</link><pubDate>Tue, 14 Jun 2022 00:24:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/06/2022-06-11-view-making-some-of-the-ifs-open-source/</guid><description>&lt;p&gt;本文翻译自 ECMWF 的一篇通讯文章和一篇新闻，介绍 ECMWF 模式 IFS 正在进行的开源活动。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An open-source Integrated Forecasting System&lt;/p&gt;
&lt;p&gt;by Michael SleighWillem DeconinckMichael LangeOlivier MarsdenBalthasar Reuter&lt;/p&gt;
&lt;p&gt;Number 171 - Spring 2022 (Published in April 2022)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/newsletter/171/news/open-source-integrated-forecasting-system"&gt;https://www.ecmwf.int/en/newsletter/171/news/open-source-integrated-forecasting-system&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Making some of the Integrated Forecasting System open source&lt;/p&gt;
&lt;p&gt;9 June 2022&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2022/making-some-integrated-forecasting-system-open-source"&gt;https://www.ecmwf.int/en/about/media-centre/news/2022/making-some-integrated-forecasting-system-open-source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以下&lt;strong&gt;正文&lt;/strong&gt;章节是对该文章的节选翻译，并根据笔者个人理解有所修改，如有偏差敬请谅解。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;ECMWF 的集成预报系统 (Integrated Forecasting System, IFS) 的部分组件正变为开源，未来将与会员国协商审查将整个 IFS 转为开源的优点。&lt;/p&gt;
&lt;h3 id="现状"&gt;现状&lt;/h3&gt;
&lt;p&gt;目前，IFS 的源代码和其他 ECMWF 代码在许可方法上有所区别。
非 IFS 软件通常在开源许可 (Apache‑2) 下可用，而 IFS 的使用则更加严格。
IFS 源代码不公开，只能由 ECMWF 及其成员国和合作国访问。
IFS 的 “开放” 版本确实存在，被称为 OpenIFS，可供气象研究机构使用，但这不是完全的开源，使用它需要定制许可证。&lt;/p&gt;</description></item><item><title>共青团建团100周年讲话心得</title><link>https://blog.perillaroc.wang/post/2022/05/2022-05-26-thoughts-about-speech-on-100th-anniversary-of-gqt/</link><pubDate>Thu, 26 May 2022 22:42:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/05/2022-05-26-thoughts-about-speech-on-100th-anniversary-of-gqt/</guid><description>&lt;blockquote&gt;
&lt;p&gt;注：本文是我在单位部门支部交流会上的发言稿&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;志存高远方能登高望远，胸怀天下才可大展宏图&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我今年刚好是本命年 36 岁，按照青年学习小组的标准，还算是青年，但按照国家自然科学基金青年科学基金项目的标准，已经不是青年了。
35 到 40 岁之间正处于既是青年又是中年的叠加状态，所以我就从两个角度来谈下自己的感想。&lt;/p&gt;
&lt;p&gt;总书记在讲话中说到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;越是往前走、向上攀，越是要善于从走过的路中汲取智慧、提振信心、增添力量。
这是共青团面向未来、再立新功的重要遵循。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;总书记告诉我们应该从过去工作经历中总结经验教训。
回看我参加工作的九年时间，最重要的问题就是缺乏明确的工作目标，频繁切换工作方向，走的都是弯路，导致人到中年却还是缺少核心竞争力。&lt;/p&gt;
&lt;p&gt;总书记在讲话中提到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;只有坚持党的领导，共青团才能团结带领青年前进，推动中国青年运动沿着正确政治方向前行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;工作也是一样，如果缺乏有效指导，自己艰难探索前行道路，很容易走弯路，白费了宝贵的青年时光。
我建议大家积极寻找领路人，要学会抱大腿，才能沿着正确的工作方向前行。&lt;/p&gt;
&lt;p&gt;作为一名青年，我更应该有明确的奋斗目标。
总书记在讲话中提到：
历史充分证明，只有牢牢扭住为中华民族伟大复兴而奋斗这一主题，共青团才能团结起一切可以团结的青春力量，唱响壮丽的青春之歌。&lt;/p&gt;
&lt;p&gt;青年的命运从来都与时代紧密相连，我应该向社会主义革命和建设时期的前辈们学习，向科学进军，向困难进军，向荒原进军。
俄乌战争强化了自主数值预报模式的重要性，我们中心正处在发展的关键时期，在单位需要的时候，我们青年人要能冲得出来，顶得上去。
我们应该把握住这一关键历史机遇，充分发挥身处国家级平台的优势，将个人的发展与祖国的发展需要紧密结合起来，强化责任意识，激发担当精神，培养严谨务实的工作作风，保持积极向上的工作态度，为数值预报事业贡献自己的力量。&lt;/p&gt;
&lt;p&gt;最后，引用大会前央视短片中冬奥冠军武大靖说的一句话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;青年就要拼一拼，说不定梦想就实现了。&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>视界：ECMWF在Maestro项目中的借调</title><link>https://blog.perillaroc.wang/post/2022/02/2022-02-18-view-secondment-at-ecmwf-on-the-maestro-project/</link><pubDate>Mon, 23 May 2022 22:51:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/02/2022-02-18-view-secondment-at-ecmwf-on-the-maestro-project/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Secondment at ECMWF on the Maestro project&lt;/p&gt;
&lt;p&gt;by Domokos Sarmany and Miloš Lompar&lt;/p&gt;
&lt;p&gt;31 January 2022&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/about/media-centre/science-blog/2022/secondment-ecmwf-maestro-project"&gt;https://www.ecmwf.int/en/about/media-centre/science-blog/2022/secondment-ecmwf-maestro-project&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原文发表于 ECMWF 网站科学博客文章《&lt;a href="https://www.ecmwf.int/en/about/media-centre/science-blog/2022/secondment-ecmwf-maestro-project"&gt;Secondment at ECMWF on the Maestro project&lt;/a&gt;》，介绍在 Maestro 项目中借调人员 Miloš Lompar 的工作。&lt;/p&gt;
&lt;p&gt;以下正文章节是对该文章的节选翻译，并根据笔者个人理解有所修改，如有偏差敬请谅解。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="数值天气预报可以生成多少预报数据"&gt;数值天气预报可以生成多少预报数据？&lt;/h3&gt;
&lt;p&gt;非常多，但远远不够。&lt;/p&gt;
&lt;p&gt;ECMWF 的 IFS 目前每天生成 120 TiB 业务预报数据。
但更准确的天气预报需要提高模式分辨率，意味着当前数据量与未来预报将产生的数据量相比相形见绌。
这就带来了技术挑战。&lt;/p&gt;
&lt;p&gt;数值天气预报 (NWP) 一直是高性能计算 (HPC) 领域技术创新的早期采用者，并部署了世界上性能最好的一些超级计算机。
最新的例子是 ECMWF 即将推出的 ATOS 超算。
然而，多年来，科学家面临的技术挑战发生了变化。&lt;/p&gt;
&lt;p&gt;几十年来，执行浮点运算 (floating-point operations, flops) 的绝对速度和相关计算成本是主要问题，带来针对浮点运算进行优化的软件栈和编程模型，但将数据处理视为二等公民。
在内存中访问足够的数据以及最近以来的存储吞吐量，在过去的二十年中已成为重大瓶颈 ———— 这种现象通常被称为 &lt;strong&gt;IO 性能差距&lt;/strong&gt; (performance gap)。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/view/0218-ecmwf-maestro/BullSequana-supercomputer-690px.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自原文，ECMWF 的下一台超级计算机将由四个 Atos BullSequana XH2000 集群组成，并计划于 2022 年投入使用&lt;/em&gt;&lt;/p&gt;</description></item><item><title>视界：将ECMWF新的高性能计算基础设施投入业务运行</title><link>https://blog.perillaroc.wang/post/2022/05/2022-05-14-view-taking-ecmwfs-new-high-performance-computing-facility-operation/</link><pubDate>Sat, 14 May 2022 16:02:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/05/2022-05-14-view-taking-ecmwfs-new-high-performance-computing-facility-operation/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Taking ECMWF’s new high-performance computing facility into operation&lt;/p&gt;
&lt;p&gt;9 May 2022&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2022/taking-ecmwfs-new-high-performance-computing-facility-operation"&gt;https://www.ecmwf.int/en/about/media-centre/news/2022/taking-ecmwfs-new-high-performance-computing-facility-operation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原文发表于 ECMWF 官网新闻《&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2022/taking-ecmwfs-new-high-performance-computing-facility-operation"&gt;Taking ECMWF’s new high-performance computing facility into operation&lt;/a&gt;》，介绍 ECMWF 计算部副主任 Christine Kitchen 在 ECMWF 新一代 HPC 方面的相关工作。&lt;/p&gt;
&lt;p&gt;以下正文章节是对该文章的节选翻译，并根据笔者个人理解有所修改，如有偏差敬请谅解。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;位于意大利博洛尼亚的新高性能计算设施 (High performance computing facility, HPCF) 由 4 个 Atos BullSequana XH2000 综合体组成，将替换 ECMWF 在英国雷丁由两台 Cray XC40 集群构成的现有系统。
新 HPC 服务将提供相对于当前系统大约 5 倍的性能提升。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/view/0514-ecmwf-hpcf/ECMWF-Data-Centre-Sep-2021-690px.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;位于意大利 Bologna 的 ECWMF 新数据中心的 Atos HPCF&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="测试新-hpcf"&gt;测试新 HPCF&lt;/h3&gt;
&lt;p&gt;Christine 加入 ECMWF 时，大部分新 HPCF 已经安装在博洛尼亚。
她现在需要完成将超级计算机投入运行的最后阶段。&lt;/p&gt;</description></item><item><title>使用Lark创建JSON解析器</title><link>https://blog.perillaroc.wang/post/2022/05/2022-05-07-lark-tutorial-json-parser/</link><pubDate>Sun, 08 May 2022 10:41:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/05/2022-05-07-lark-tutorial-json-parser/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自 Lark 官方教程《&lt;a href="https://lark-parser.readthedocs.io/en/latest/json_tutorial.html"&gt;JSON parser - Tutorial&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/lark-parser/lark"&gt;Lark&lt;/a&gt; 是一个 Python 实现的语法解析器，接受语法和文本，并生成表示该文本的结构树。&lt;/p&gt;
&lt;p&gt;本文使用 Lark 创建 JSON 解析器，简要说明 Lark 的使用方法。&lt;/p&gt;
&lt;h2 id="语法"&gt;语法&lt;/h2&gt;
&lt;p&gt;Lark 支持 &lt;a href="https://www.wikiwand.com/en/Extended_Backus%E2%80%93Naur_form"&gt;EBNF&lt;/a&gt; 语法格式。
基本格式如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bnf" data-lang="bnf"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rule_name : list of rules and TERMINALS to match
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | another possible list of items
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | etc.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TERMINAL: &amp;#34;some text to match&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;terminal 是一个字符串或一个正则表达式。&lt;/p&gt;
&lt;p&gt;对于每条规则，解析器会通过顺序匹配它的所有项目 (右侧)，尝试每个备选方案。&lt;/p&gt;
&lt;p&gt;JSON 示例中，规则结构比较简单：一个 json 文档要么是一个列表，要么是一个字典，要么是一个字符串/数字/等等。
字典和列表是递归的，包含其它 json 文档 (或称为 &amp;ldquo;values&amp;rdquo;)。&lt;/p&gt;
&lt;p&gt;使用 EBNF 格式写上述结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bnf" data-lang="bnf"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;value: dict
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | list
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | STRING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | NUMBER
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | &amp;#34;true&amp;#34; | &amp;#34;false&amp;#34; | &amp;#34;null&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;list : &amp;#34;[&amp;#34; [value (&amp;#34;,&amp;#34; value)*] &amp;#34;]&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dict : &amp;#34;{&amp;#34; [pair (&amp;#34;,&amp;#34; pair)*] &amp;#34;}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pair : STRING &amp;#34;:&amp;#34; value
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;语法解释：&lt;/p&gt;</description></item><item><title>CEMC笔记：业务系统任务运行超时的两种检测方法</title><link>https://blog.perillaroc.wang/post/2022/04/2022-04-21-make-long-run-job-error/</link><pubDate>Thu, 21 Apr 2022 20:41:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/04/2022-04-21-make-long-run-job-error/</guid><description>&lt;p&gt;数值预报业务系统是由大量有依赖关系的任务构成的工作流。
如果某个任务运行超时，那么依赖该任务的后续任务都不会运行，甚至会影响下一个时次预报的按时启动。
所以需要及时发现运行超时的任务，根据不同的任务采取不同的处理方法，例如重新启动任务或者继续等待运行结束。&lt;/p&gt;
&lt;p&gt;本文介绍目前 CEMC 在 CMA-PI HPC 中的数值模式业务系统任务脚本中使用的两种超时检测方法。&lt;/p&gt;
&lt;h2 id="slurm-墙钟时间"&gt;Slurm 墙钟时间&lt;/h2&gt;
&lt;p&gt;业务系统中的绝大部分作业都在 Slurm 队列中运行，可以通过设置 Slurm 的墙钟时间来控制任务运行时长。
slurm 会终止运行时间超过墙钟时间的任务，导致脚本运行出错。&lt;/p&gt;
&lt;p&gt;例如，下面代码来自 CMA-MESO 产品后处理转码任务脚本的文件头，其中 &lt;code&gt;#SBATCH -t 00:60:00&lt;/code&gt; 设置墙钟时间为60 分钟。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#!/bin/ksh
#SBATCH --comment=op_grapes_meso_3km
#SBATCH -J GRAPES
#SBATCH -N 4
#SBATCH --ntasks-per-node=32
#SBATCH -t 00:60:00
#SBATCH -p operation
#SBATCH -o job_001.1
#SBATCH -e job_001.1.err
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是预防任务超时的最后一道防线，所以超时时间通常设置会比较宽松，仅在极端情况下才会启用。&lt;/p&gt;
&lt;h2 id="timeout-命令"&gt;timeout 命令&lt;/h2&gt;
&lt;p&gt;最近我们遇到任务触发 slurm 超时但 ecFlow 任务没有出错结束的情况，不清楚具体原因，但需要寻找处理方案。&lt;/p&gt;
&lt;p&gt;出错的任务都是在执行 &lt;code&gt;cp&lt;/code&gt; 文件拷贝操作，需要使用额外机制对该操作进行超时监控并报错。&lt;/p&gt;
&lt;p&gt;Linux 的 &lt;code&gt;timeout&lt;/code&gt; 命令可以实现这个功能，监控命令是否在时限内结束，超时会返回非 0 错误码。&lt;/p&gt;
&lt;p&gt;命令格式&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;timeout duration command [args]...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;duration&lt;/code&gt; 是浮点格式的时长，可以附件 &lt;code&gt;s&lt;/code&gt;（秒，默认）、&lt;code&gt;m&lt;/code&gt;（分）、&lt;code&gt;h&lt;/code&gt;（小时）、&lt;code&gt;d&lt;/code&gt;（天）字符结尾。&lt;/p&gt;</description></item><item><title>2022年第一季度工作总结</title><link>https://blog.perillaroc.wang/post/2022/04/2022-04-03-2022-q1-summary/</link><pubDate>Thu, 14 Apr 2022 20:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/04/2022-04-03-2022-q1-summary/</guid><description>&lt;p&gt;上季度工作总结中的豪情没能延续到第一季度，只剩下“&lt;strong&gt;雄关漫道真如铁&lt;/strong&gt;”，而没有了“而今迈步从头越”。&lt;/p&gt;
&lt;p&gt;部门两个科之间的分裂愈演愈烈，在部门领导人选上的分歧又看起来不可调和，整个部门弥漫在一种前途未卜的气氛中。
无论是处室内部的沟通理解还是中心对处室的信任都没能看到鼓舞人心的变化，有一种滑向恶性循环的趋势。
从非官方渠道了解的信息可以明显看到，运行团队的核心诉求和中心对处室的要求存在一定错位，我认为核心原因不在于对相关工作的不了解，也不在于沟通不到位，而是我们确实没有一项核心技术在手。
过往的工作成绩中没有一项成果可以强有力地支撑中心的研发工作，导致中心对运行团队存在质疑，认为我们只是在做业务运维工作，也只能做业务运维工作，很难去支持团队核心诉求。
当然这只是我个人的不负责任分析，部门和团队工作不属于这篇工作总结的内容。&lt;/p&gt;
&lt;p&gt;至于我个人的问题就更突出了。
我依然没能克服自己专注度不够的问题，频繁切换工作方向，没能找到可以持续深入研究的一项工作内容。
不是将精力分散到没有产出的各类任务中，就是在纠结自己究竟该进行哪项工作。
工作计划绝对不能太多，要主次分明，明确自己的主攻方向，并持续开展研发工作，遇到困难不要退缩，要有自己能趟出一条路的坚定信念。
另外，在单位内部风云变幻的特殊时期，更要保持对自己的信心，无论对过去的工作成绩、现在的工作任务和未来的工作方向，都不要因为这样或那样的质疑而轻易否定自己。
不管中心对部门有何观感，自己的路还需要自己走下去，未来的方向也必须靠自己去探索。&lt;/p&gt;
&lt;h2 id="计划完成情况"&gt;计划完成情况&lt;/h2&gt;
&lt;p&gt;第一季度再次证明我做的计划没有任何计划性可言，绝大部分任务连看都没看，少部分有所进展的工作也没有连贯性，缺乏完整而连续的规划，仅完成了 1-2 项工作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;青年基金课题
&lt;ul&gt;
&lt;li&gt;🚧 完善示例，对比运行效率&lt;/li&gt;
&lt;li&gt;❌ 技术文档&lt;/li&gt;
&lt;li&gt;❌ 并行计算技术&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;模式要素库
&lt;ul&gt;
&lt;li&gt;调研：✔️ cfgrib 索引，❌ FDB 索引&lt;/li&gt;
&lt;li&gt;❌ 元数据&lt;/li&gt;
&lt;li&gt;🚧 本地文件索引&lt;/li&gt;
&lt;li&gt;🚧 索引读取接口原型&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;产品制作融入天擎
&lt;ul&gt;
&lt;li&gt;🚧 数据准备工作&lt;/li&gt;
&lt;li&gt;❌ 部署绘图算法&lt;/li&gt;
&lt;li&gt;❌ 流程测试&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;后处理系统流程
&lt;ul&gt;
&lt;li&gt;❌ 优化运行脚本，统一编码风格&lt;/li&gt;
&lt;li&gt;❌ 通用框架&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据准备工具库 &lt;a href="https://github.com/nwpc-oper/reki"&gt;reki&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;❌ 文档&lt;/li&gt;
&lt;li&gt;❌ 测试用例&lt;/li&gt;
&lt;li&gt;🚧 完善 CMADaaS 数据检索库 &lt;a href="https://github.com/perillaroc/nuwe-cmadaas-python"&gt;nuwe-cmadaas-python&lt;/a&gt;，设计多重配置文件，实现常用检索功能&lt;/li&gt;
&lt;li&gt;🚧 GRIB 2 数据索引，❌ 与模式要素库结合&lt;/li&gt;
&lt;li&gt;❌ 更多数据处理操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;工作流软件 &lt;a href="https://github.com/perillaroc/takler"&gt;takler&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;✔️ 重启 takler 开发&lt;/li&gt;
&lt;li&gt;🚧 Python 实现&lt;/li&gt;
&lt;li&gt;🚧 简单顺序流程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;绘图封装工具库 &lt;a href="https://github.com/nwpc-oper/sokort"&gt;sokort&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;✔️ 替换 WMC 绘图&lt;/li&gt;
&lt;li&gt;❌ Singularity 镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据检查工具 &lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-data-client&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;❌ 并发检测拷贝，串行修改数据进度&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;绘图包 &lt;a href="https://github.com/perillaroc/meda"&gt;meda&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;❌ 设计绘图 API 接口&lt;/li&gt;
&lt;li&gt;❌ 支持中国分区域图片&lt;/li&gt;
&lt;li&gt;❌ 绘制部分业务系统图形&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="业务系统"&gt;业务系统&lt;/h3&gt;
&lt;h4 id="冬奥保障"&gt;冬奥保障&lt;/h4&gt;
&lt;p&gt;第一季度最重要的工作就是 2022 北京冬奥会保障服务，部门承担数值天气预报业务系统的值班值守任务。
中心要求值班员在包含春节假期在内的特殊保障时期必须值班值守，也就是夜间值班需要待在单位大院内。
虽然不需要像以往特殊保障时期那样夜间必须待在值班室，但这也是我参加工作以来参与的最长时间的特殊保障值班任务了。
这项任务直接促使科级部门在 3 月对值班值守方案、系统升级办法展开热烈而充分的讨论，逐步形成共识，将在第二季度形成正式发布的文件。&lt;/p&gt;</description></item><item><title>读书笔记：置身事内</title><link>https://blog.perillaroc.wang/post/2022/04/2022-04-10-book-zhi-shen-shi-nei/</link><pubDate>Sun, 10 Apr 2022 21:38:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/04/2022-04-10-book-zhi-shen-shi-nei/</guid><description>&lt;p&gt;本文记录 2022 年 4 月在读书小组发的一篇读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;《置身事内：中国政府与经济发展》兰小欢&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/book/202204-zhi-shen-shi-nei/douban.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自豆瓣&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;一本通俗易懂的政治经济学科普书籍，正如作者在序言中所说，“本书力求简明扼要，突出主要逻辑和重点事实”，但作者依然标注了大量参考文献，并在每章末尾列出扩展阅读材料。
本书以地方政府投融资为主线，介绍地方政府的基本事务、收入、支出、土地融资和开发、投资和负债，并解释这些微观行为对宏观现象的影响，包括城市化和工业化、房价、地区差异、债务风险、国内经济结构失衡、国际贸易冲突等。
作者在讲到地方政府的城市化发展模式时认为以土地为中心的城市化忽略了城市化的真正核心：&lt;strong&gt;人&lt;/strong&gt;，并非常典型地总结到：&lt;strong&gt;梦想买不起，故乡回不去&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;作者针对目前问题给出的药方我总结为三点：生产型政府向服务型政府转变；人口自由流动，向大城市集中；大城市要大力发展服务业，工业未来不会创造岗位。
但我对部分药方不太赞同。
作者强调人均GDP的平衡，认为不应该限制人口流动，让人力自愿流向大城市，拉低人均GDP，也就能维持服务业的低人力成本。
作者认为未来工业不会创造岗位，解决就业和提高收入必须依靠服务业的大发展，而这只能发生在人口密集的城市中。
感觉还是牺牲一部分人的利益来维护另一批人的思路，有点儿像农业工业剪刀差的翻版，利用服务业的低人力成本来留住“高端人才”。
而且大量聚集的服务业也会抬高特定地段的地价。从最近上海疫情来看，一家独大的发展模式应对未来风险的能力太差，有必要让各个地区均衡发展。&lt;/p&gt;
&lt;p&gt;读过全书受益最大的是第一章，介绍政府间事权划分的基本逻辑，包括事权划分三原则：外部性和受益范围原则、信息复杂性原则、激励相容原则。
后两项在平时工作中就体现得非常明显。
信息优势的一方拥有决策优势，获取和传递信息需要花费大量时间经历，作为信息载体的文件和会议成为权力的载体之一，也就需要一套复杂的文件和会议制度。
权力实质是在说不清楚的情况下由谁来拍板决策的问题。
做任何事都有代价，最优的结果是让效果和代价匹配，而不是不计代价地达成目标。
政绩和晋升对地方一把手和领导班子成员非常重要，却无法激励绝大多数公务员，他们最在意的激励并不是晋升，而是实际收入以及一些工作福利，包括工资、奖金、补助、补贴、实惠的食堂、舒适的办公条件等等。
但外部奖励需要看得见的工作业绩，而绝大多数工作都没有清清楚楚且可以实际衡量的业绩，因此需要使命感、价值观、愿景等种种与内心感受相关的驱动机制。
这与业务运行工作及其类似，很难明确体现工作量，就得从其他能衡量工作量的工作上体现自身价值。&lt;/p&gt;
&lt;p&gt;书中介绍的政府事务内容都可以在事业单位找到相似之处，多了解政府的工作决策机制也有利于在单位更高效地开展工作。
成功的政策背后是成功的协商和妥协，而不是机械的命令与执行。
不存在脱离了具体场景、放之四海而皆准的答案，必须具体问题具体分析，并根据现实变化不断调整。&lt;/p&gt;
&lt;p&gt;用全书最后章节的一句话做结：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;相信中国会更好&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/35546622/"&gt;豆瓣《置身事内》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>CEMC笔记：CMA-TYM中使用CMA-GFS模式面数据驱动的流程改造</title><link>https://blog.perillaroc.wang/post/2022/04/2022-04-07-workflow-upload-to-use-gfs-modelvar-in-tym/</link><pubDate>Thu, 07 Apr 2022 14:43:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/04/2022-04-07-workflow-upload-to-use-gfs-modelvar-in-tym/</guid><description>&lt;p&gt;本文介绍对 CMA-TYM 中使用CMA-GFS模式面数据驱动的 ecFlow 流程改造。
在 ecFlow 不支持分支流程的情况下，使用动态生成的标识文件模拟流程分支。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;1 月初 NMIC 接收 NCEP 资料发生问题，CMA-TYM 切换背景场数据发现使用 CMA-GFS 等压面做背景场会导致积分无法进行。
经过研发部门同事紧急开发，CMA-TYM 将备份方案从 CMA-GFS 等压面驱动改为模式面驱动，并顺利完成后续的应急演练任务。&lt;/p&gt;
&lt;h2 id="业务流程"&gt;业务流程&lt;/h2&gt;
&lt;p&gt;CMA-TYM 使用 CMA-GFS 等压面和等模式面数据驱动的流程如下图所示。
使用 CMA-GFS 等压面数据时，NCEP 与 CMA 流程相同，仅生成 bcgk 的方法不同。
但使用 CMA-GFS 等模式面数据时，CMA 流程需要跳过部分任务，同时使用不同版本的 psi 和 forecast 可执行程序。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/summary/q1/cma-tym-gfs-bckg.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;CMA-TYM 使用 NCEP 和 CMA-GFS 背景场的流程示意图。(a) 原有使用 CMA-GFS 等压面驱动的业务流程；(b) 使用 CMA-GFS 模式面驱动的业务流程&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="构建运行流程"&gt;构建运行流程&lt;/h2&gt;
&lt;p&gt;构建运行流程时的直观想法是使用分支结构，不同数据源执行不同分支上的任务。
但 ecFlow 不支持分支结构，使用 complete + trigger 模拟分支失败。&lt;/p&gt;
&lt;p&gt;当前 CMA-TYM 业务系统使用&lt;strong&gt;标识文件&lt;/strong&gt;的方式来构建流程，如下图所示。
check_ncep 任务检测 NCEP 背景场是否完整，生成 bckg_set.sh 脚本，包含 &lt;code&gt;user_cma&lt;/code&gt; 和 &lt;code&gt;use_ncep&lt;/code&gt; 两个标识变量。如果使用 CMA-GFS 数据，则脚本内容为：&lt;/p&gt;</description></item><item><title>获取Slurm作业运行时间</title><link>https://blog.perillaroc.wang/post/2022/03/2022-03-31-get-slurm-job-running-time/</link><pubDate>Sat, 02 Apr 2022 15:36:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/03/2022-03-31-get-slurm-job-running-time/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2022/03/2022-03-24-create-slurm-jobs-using-jinja2/"&gt;使用Jinja2批量生成Slurm作业脚本&lt;/a&gt;》介绍如何批量编写作业脚本。
批量提交作业的目的是统计作业运行耗时，本文介绍如何使用 Python 通过执行 sacct 命令批量获取 Slurm 作业的运行时间。&lt;/p&gt;
&lt;h2 id="方法"&gt;方法&lt;/h2&gt;
&lt;p&gt;Slurm 的 &lt;code&gt;sacct&lt;/code&gt; 命令可以获取作业相关运行数据。&lt;/p&gt;
&lt;p&gt;默认参数 &lt;code&gt;sacct&lt;/code&gt; 命令输出如下所示，仅给出基本信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sacct
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; JobID JobName Partition Account AllocCPUS State ExitCode
------------ ---------- ---------- ---------- ---------- ---------- --------
38407636 reki normal acct4 32 COMPLETED 0:0
38407636.ba+ batch acct4 32 COMPLETED 0:0
38407636.0 python acct4 32 COMPLETED 0:0
38407637 reki normal acct4 32 COMPLETED 0:0
38407637.ba+ batch acct4 32 COMPLETED 0:0
38407637.0 python acct4 32 COMPLETED 0:0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;启用扩展参数的 &lt;code&gt;sacct&lt;/code&gt; 命令显示时间信息：&lt;/p&gt;</description></item><item><title>使用Jinja2批量生成Slurm作业脚本</title><link>https://blog.perillaroc.wang/post/2022/03/2022-03-24-create-slurm-jobs-using-jinja2/</link><pubDate>Thu, 24 Mar 2022 22:10:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/03/2022-03-24-create-slurm-jobs-using-jinja2/</guid><description>&lt;p&gt;课题项目对比 HPC 上数据处理算法在不同节点数下的运行时间。
为了得到有说服力的结果，需要多次运行同一测试用例并统计运行时间。
不过，多次重复运行同一个脚本的结果往往不够准确，反复读取相同数据可能受 HPC 并行文件系统缓存机制影响而导致速度变快。
因此最好能在每次运行时使用不同的数据。&lt;/p&gt;
&lt;p&gt;一种方案是使用单一作业脚本，在 Python 代码中随机选择数据目录，但该方案的作业脚本每次运行都会使用不同的输入数据，不利于结果重现。
因此，本文批量生成作业脚本，数据目录在脚本生成时随机定义并写入到作业脚本中。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 Python 模板库 Jinja2 批量生成 Slurm 作业脚本。
可以看到仅使用 Jinja2 提供的最基础的模板功能就能实现作业脚本的自动批量生成。&lt;/p&gt;
&lt;h2 id="创建模板"&gt;创建模板&lt;/h2&gt;
&lt;p&gt;首先创建 Slurm 作业运行需要的 Shell 脚本模板。&lt;/p&gt;
&lt;p&gt;使用 Jinja2 模板的两种语法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;变量替换: &lt;code&gt;{{ variable_name }}&lt;/code&gt;，将替换为变量的值，主要用于将运行参数导入到模板中&lt;/li&gt;
&lt;li&gt;条件语句：&lt;code&gt;{%- if %} ... {%- else %} ... {%- endif %}&lt;/code&gt;，根据条件输出不同的代码段，主要用于为串行作业和并行作业配置不同的参数和脚本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;定义 Slurm 参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH -J reki&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH -p {{ partition }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;%- &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; is_parallel %&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH -N {{ nodes }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH --ntasks-per-node={{ ntasks_per_node }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;{&lt;/span&gt;%- endif %&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH -o {{ job_name }}.%j.out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH -e {{ job_name }}.%j.err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH --comment=Grapes_gfs_post&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#SBATCH --no-requeue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中模板参数 &lt;code&gt;is_parallel&lt;/code&gt; 表示作业是否为并行作业。
串行作业仅需要设置队列 &lt;code&gt;partition&lt;/code&gt;，并行作业还需要设置节点数 &lt;code&gt;nodes&lt;/code&gt; 和每个节点的任务数 &lt;code&gt;ntasks_per_node&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>不同打包方式下GRIB2文件加载速度对比：简单打包与JPEG压缩</title><link>https://blog.perillaroc.wang/post/2022/03/2022-03-13-grib-notebook-load-speed-with-different-grib2-packing-type/</link><pubDate>Sun, 20 Mar 2022 22:14:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/03/2022-03-13-grib-notebook-load-speed-with-different-grib2-packing-type/</guid><description>&lt;p&gt;GRIB 2 格式文件支持使用不同方式保存要素场数据，可以使用二维数组的一维展开，也可以使用类似 JPEG、PNG 等图片格式对二维数据进行压缩。&lt;/p&gt;
&lt;p&gt;本文介绍不同打包方式下从 GRIB 2 文件中加载要素场的速度。&lt;/p&gt;
&lt;h2 id="打包方式"&gt;打包方式&lt;/h2&gt;
&lt;p&gt;不同中心生成的 GRIB 2 数据使用不同的打包方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMA 天气预报模式：JPEG2000 压缩 (grid_jpeg)&lt;/li&gt;
&lt;li&gt;ECMWF 公开数据：简单打包，无压缩 (grid_simple)&lt;/li&gt;
&lt;li&gt;NCEP GFS：复杂打包 (grid_complex_spatial_differencing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文测试 wgrib2 支持的部分打包方式，如下表所示：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;wgrib2 name&lt;/th&gt;
					&lt;th&gt;eccodes packingType&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;jpeg&lt;/td&gt;
					&lt;td&gt;grid_jpeg&lt;/td&gt;
					&lt;td&gt;JPEG2000 压缩&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;simple&lt;/td&gt;
					&lt;td&gt;grid_simple&lt;/td&gt;
					&lt;td&gt;无压缩，打包缩放后的整数&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ieee&lt;/td&gt;
					&lt;td&gt;grid_ieee&lt;/td&gt;
					&lt;td&gt;IEEE 格式 (每个数据点 4 字节)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;complex1&lt;/td&gt;
					&lt;td&gt;grid_complex&lt;/td&gt;
					&lt;td&gt;complex packing&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;complex2&lt;/td&gt;
					&lt;td&gt;grid_complex_spatial_differencing&lt;/td&gt;
					&lt;td&gt;complex packing, pack increments (deltas)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;complex3&lt;/td&gt;
					&lt;td&gt;grid_complex_spatial_differencing&lt;/td&gt;
					&lt;td&gt;complex packing, pack increments after linear extrapolation&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;aec&lt;/td&gt;
					&lt;td&gt;grid_ccsds&lt;/td&gt;
					&lt;td&gt;使用 libaec 实现的 CCSDS 压缩&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;使用 CMA-MESO V5.1 的等压面产品作为测试数据，原始文件使用 JPEG 方式压缩。&lt;/p&gt;</description></item><item><title>读书笔记：女性贫困</title><link>https://blog.perillaroc.wang/post/2022/03/2022-03-13-book-nv-xing-pin-kun/</link><pubDate>Sun, 13 Mar 2022 10:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/03/2022-03-13-book-nv-xing-pin-kun/</guid><description>&lt;p&gt;本文记录 2022 年 2 月在读书小组发的一篇读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;《女性贫困》[日] NHK特别节目录制组&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/book/202203-nv-xing-pin-kun/douban.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自豆瓣&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2017年的一本书，没想到发达国家日本也会有年轻女性的贫困问题。
书中从非正式雇用、单身母亲、色情业、非婚生子、代际传递等几个方面入手，列举大量真实案例。书中没有展开深入探讨，仅在最后一章尝试寻找解决方法，提到社会援助、雇用问题、福利保障等等。
前言中提到工厂外迁导致工作减少，信息化和业务外包导致会计工作减少，接收女性的服务行业降低人工费，可以看到产业空心化的问题。
结合最近二十年日本低于4%的GDP增长率，也许当未来经济发展减速的时候，也同样会遇到书中描述的各类问题，为了应对未来的不确定性，还是要抓住当前教育能提供的机遇，保持工作竞争力。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/27111185/"&gt;豆瓣《女性贫困》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>读书笔记：张医生与王医生</title><link>https://blog.perillaroc.wang/post/2022/03/2022-03-13-book-zhang-yi-sheng-yu-wang-yi-sheng/</link><pubDate>Sun, 13 Mar 2022 10:36:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/03/2022-03-13-book-zhang-yi-sheng-yu-wang-yi-sheng/</guid><description>&lt;p&gt;本文记录 2022 年 3 月第一周在读书小组发的一篇读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;《张医生与王医生》伊险峰/杨樱&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/book/202203-zhang-yi-sheng-yu-wang-yi-sheng/douban.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自豆瓣&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;作者通过自己两位医生高中同学家庭的奋斗经历，描述过去三十年沈阳的沉浮，探寻后计划经济时代沈阳衰落的原因。
但无论是两位主人公家庭的典型程度，还是本书的分析论证，都无法支撑作者的野心。
这是参加读书小组以来读得最纠结的一本书，书中描述的各种社会现象和社会氛围正是我成为北漂的关键原因，但书中对现象的某些深入分析却和我的认知相左，甚至有些论断在我看来已经到了离谱的程度。&lt;/p&gt;
&lt;p&gt;全书以工人阶级实现向中产阶级的阶级跃升为主线，从工业城市、单位社会、稀缺经济、工人阶级文化、男性气概、重大历史事件和时代变迁等不同方面来描述沈阳文化中的“社会”到底是什么，并试图分析沈阳乃至整个东北为什么会衰落。
书中很多论证看起来像是为了说明而说明，与主人公家庭没有任何联系。
很多论证在我看来并不成立。比如作者将八十年代沈阳就业率高双职工家庭多归结为穷，将沈阳对计划生育的严格控制归结为钱和文明程度等等，这就是极其离谱的观点了。
同时，非常遗憾的是作者似乎将东北衰落归结为地区的人文环境，没有提及九十年代以来苏联解体、朝核问题对东北亚地缘政治的深刻影响。&lt;/p&gt;
&lt;p&gt;从诸如“1949年XX建政”等描述方式来看，作者似乎想保持游离于政府之外的“知识分子”形象。
作者认为城市由消费驱动，用美国的例子来说明城市是为中产阶级提供服务的，没有产业工人的位置。
书中也频繁引用研究英国三十年代工人阶级的论著来对比沈阳的八九十年代。
我很难赞同城市乃至国家发展只有英美一种模板，产业空心化的危害已然显现，我们需要走出与资本主义不一样的发展道路。&lt;/p&gt;
&lt;p&gt;从个人经历来看，两位主人公家庭脱颖而出在于对教育的重视，更在于选择医生这个随着人们生活水平提高而需求量越来越大的职业，而医生正是书中所说工人阶级更喜欢的手艺人，通过积累经验可以持续保持个人竞争力。
以两位主人公为代表的 70 后一代人享受到了国家高速发展的红利，乘时代东风可以完成人生逆袭。
教育曾经是改变人生的各种路线中最容易实现的一种，而未来却不一定还能有这样的机遇，所以不相信奋斗还能相信啥，让我们投入到内卷的大业中吧。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/35623209/"&gt;豆瓣《张医生与王医生》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>GRIB笔记：cfgrib索引机制解析v1</title><link>https://blog.perillaroc.wang/post/2022/02/2022-02-18-cfgrib-index-v1/</link><pubDate>Mon, 21 Feb 2022 16:08:24 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/02/2022-02-18-cfgrib-index-v1/</guid><description>&lt;p&gt;&lt;a href="https://github.com/ecmwf/cfgrib"&gt;cfgrib&lt;/a&gt; 是由 ECMWF 开发的 GRIB 格式 Python 工具库，基于 ecCodes 库实现 GRIB 格式文件的编解码。&lt;/p&gt;
&lt;p&gt;cfgrib 目前版本正在开发 v2 版索引，经测试发现 v2 版本索引实现存在一定问题，可以生成但无法被 cfgrib 读取。
本文以 v0.9.9.1 版本为例介绍 cfgrib 索引版本 1，git 提交 hash 为 af3f96c1。&lt;/p&gt;
&lt;h2 id="索引简介"&gt;索引简介&lt;/h2&gt;
&lt;p&gt;在默认参数配置下，cfgrib 会检查 GRIB 2 文件是否有索引文件存在，如果有则直接使用该文件，如果没有，则会在 GRIB 2 文件目录中生成一个索引文件。&lt;/p&gt;
&lt;p&gt;下面代码会为 &lt;code&gt;gmf.gra.2022021700006.grb2&lt;/code&gt; 文件在当前目录生成索引文件 &lt;code&gt;gmf.gra.2022021700006.grb2.02ccc.idx&lt;/code&gt;，文件名中 &lt;code&gt;02ccc&lt;/code&gt; 是 cfgrib 自动生成的 hash 编码。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;./gmf.gra.2022021700006.grb2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_dataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; engine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;cfgrib&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; backend_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;filter_by_keys&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;shortName&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;typeOfLevel&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;isobaricInhPa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第二次运行上述代码时，cfgrib 会自动加载索引文件信息，加快要素查找速度。&lt;/p&gt;</description></item><item><title>视界：扩大ECMWF数据的使用范围</title><link>https://blog.perillaroc.wang/post/2022/01/2022-01-20-view-widening-the-reach-of-ecmwfs-data/</link><pubDate>Fri, 18 Feb 2022 20:50:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2022/01/2022-01-20-view-widening-the-reach-of-ecmwfs-data/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Widening the reach of ECMWF’s data&lt;/p&gt;
&lt;p&gt;17 January 2022&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2022/widening-reach-ecmwfs-data"&gt;https://www.ecmwf.int/en/about/media-centre/news/2022/widening-reach-ecmwfs-data&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原文发表于 ECMWF 网站新闻《&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2022/widening-reach-ecmwfs-data"&gt;Widening the reach of ECMWF’s data&lt;/a&gt;》，介绍 Web 开发团队负责人 &lt;a href="https://www.ecmwf.int/en/about/who-we-are/staff-profiles/sylvie-lamy-thepaut"&gt;Sylvie Lamy-Thépaut&lt;/a&gt; 在 ECMWF 的工作。&lt;/p&gt;
&lt;p&gt;以下正文章节是对该新闻的翻译，并根据笔者个人理解有所删改，如有偏差敬请谅解。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;ECMWF 的使命是将数据提供给更多人。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sylvie Lamy-Thépaut 将气象专业知识与计算机专业知识相结合来实现这一目标。&lt;/p&gt;
&lt;h3 id="个人经历"&gt;个人经历&lt;/h3&gt;
&lt;p&gt;在 1980 年代学习气象学后，她担任了一年的预报员。
但她对通过图形计算机上的可视化技术让预报员访问预报数据更感兴趣，这是一种当时刚刚兴起的技术。&lt;/p&gt;
&lt;p&gt;她在 Météo-France 工作期间获得了计算机科学硕士学位，并在 ECMWF 工作了一段时间，帮助为其研究人员开发第一个版本的交互式工作站，称为 &lt;em&gt;Metview&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;自 2002 年以来，Sylvie 直接为 ECMWF 工作，包括 &lt;strong&gt;Metview&lt;/strong&gt; 和气象绘图软件 &lt;strong&gt;Magics&lt;/strong&gt;。
作为 Web 开发团队的负责人，自 2012 年以来，她逐渐将 ECMWF 的数据开放给更广泛的受众，并在此过程中对 ECMWF 的 Web 基础设施进行了现代化改造。&lt;/p&gt;
&lt;p&gt;她说：“我们目前正在向任何对我们数据感兴趣的人提供实时和固定分辨率的数据子集。这一原则与我们正在努力解决的一些技术挑战有关。”&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2022/view/0120-ecmwf-data/1989-Meteo-France-image_690px.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;在她职业生涯的初期，Sylvie 为 Météo-France 开发了一个可视化系统。这些图显示了位于巴黎西南 Trappes 的雷达所观测到的降水量（单位为毫米/小时）&lt;/em&gt;&lt;/p&gt;</description></item><item><title>论文阅读：面向天气和气候数据的可扩展对象存储</title><link>https://blog.perillaroc.wang/post/2021/12/2021-12-08-paper-smart-2017-fdb/</link><pubDate>Mon, 10 Jan 2022 22:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/12/2021-12-08-paper-smart-2017-fdb/</guid><description>&lt;p&gt;A Scalable Object Store for Meteorological and Climate Data&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simon D. Smart, Tiago Quintino, and Baudouin Raoult. 2017. A Scalable Object Store for Meteorological and Climate Data. In Proceedings of the Platform for Advanced Scientific Computing Conference (PASC &amp;lsquo;17). Association for Computing Machinery, New York, NY, USA, Article 13, 1–8. DOI:https://doi.org/10.1145/3093172.3093238&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍由 ECMWF 开发的 Fields Database (FDB) 第 5 版。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下内容根据笔者个人理解整理，如有偏差敬请谅解&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;数值天气预报与气候模拟处于 High Performance Computing (HPC) 与 Big Data / High Performance Data Analytics (HDPA) 社区的交叉点。
数据量快速增长给数据处理管道带来了重大的可扩展性挑战，数据在各个阶段之间的移动是其中最重要的因素之一。&lt;/p&gt;</description></item><item><title>2021年第四季度工作总结</title><link>https://blog.perillaroc.wang/post/2021/12/2021-12-31-2021-q4-summary/</link><pubDate>Mon, 10 Jan 2022 21:49:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/12/2021-12-31-2021-q4-summary/</guid><description>&lt;p&gt;第四季度的变化比想象中大很多，三个月过去我依然在适应新的环境，工作上面的进展很少。
在第三季度工作总结中我写了一堆牢骚，再来一次显然就不合适了。
新的一年在新的单位应该吸取教训，展望未来。就拿这篇总结当做对未来工作的思考吧。&lt;/p&gt;
&lt;h2 id="计划完成情况"&gt;计划完成情况&lt;/h2&gt;
&lt;p&gt;立 Flag 就是用来被打脸的，参见果壳儿网一篇文章《&lt;a href="//www.guokr.com/article/460802/"&gt;你的flag为什么总是倒？因为你把它说出来了！&lt;/a&gt;》。
第四季度的计划目标几乎都没有完成，可见我制定计划的水平实在堪忧，我在这三个月不知道都在忙些什么。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;青年基金项目
&lt;ul&gt;
&lt;li&gt;❌ 完善产品制作示例，完成效率对比&lt;/li&gt;
&lt;li&gt;❌ CMA-PI 正确使用 Dask 集群&lt;/li&gt;
&lt;li&gt;❌ 技术文档&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;技术总结
&lt;ul&gt;
&lt;li&gt;✔️ 对过去五年工作进行总结和提炼&lt;/li&gt;
&lt;li&gt;✔️ 高工评审&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;业务系统升级
&lt;ul&gt;
&lt;li&gt;✔️ MESO 5.1 升级&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据准备工具库 &lt;a href="https://github.com/nwpc-oper/reki"&gt;reki&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;❌ CMADaaS 接口库 &lt;a href="https://github.com/perillaroc/nuwe-cmadaas-python"&gt;nuwe-cmadaas-python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;❌ 更多数据处理函数&lt;/li&gt;
&lt;li&gt;🚧 编写文档，❌ CMA-PI 示例&lt;/li&gt;
&lt;li&gt;❌ CMA-PI 测试 (✔️ PC 测试)&lt;/li&gt;
&lt;li&gt;✔️ 应用：尝试实现一种 ML 算法 (除 MOML 外)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;绘图脚本工具库 &lt;a href="https://github.com/nwpc-oper/sokort"&gt;sokort&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;✔️ Python 绘图脚本&lt;/li&gt;
&lt;li&gt;⏰ 加工流水线&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;绘图包 &lt;a href="https://github.com/perillaroc/meda"&gt;meda&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;🚧 业务系统图形&lt;/li&gt;
&lt;li&gt;❌ API 接口&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据检查工具 &lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-data-client&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;❌ GO 模板&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;工作流项目 &lt;a href="https://github.com/perillaroc/takler"&gt;takler&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;❌ 重启&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="职称评审"&gt;职称评审&lt;/h3&gt;
&lt;p&gt;从 11 月 3 日接到通知开始准备申报材料，到 11 月 19 日提交材料，再到 12 月 3 日完成答辩，整个十一月 1 个月的时间都在准备高工评审相关材料。&lt;/p&gt;</description></item><item><title>视界：在EuroHPC ACROSS项目中推进高性能数据管理</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-20-view-advancing-high-performance-data-management-eurohpc-across/</link><pubDate>Fri, 07 Jan 2022 09:11:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-20-view-advancing-high-performance-data-management-eurohpc-across/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF 官方网站 2021 年 10 月 13 日发布的文章《&lt;a href="https://www.ecmwf.int/en/about/media-centre/science-blog/2021/advancing-high-performance-data-management-eurohpc-across"&gt;Advancing high-performance data management in the EuroHPC ACROSS project&lt;/a&gt;》，由 Emanuele Danovaro 撰写，版权归原作者所有。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2021/ecmwf-becomes-multi-site-organisation"&gt;Bonn 和 Bologna 开业&lt;/a&gt;的消息在 EuroHPC ACROSS 项目合作伙伴中引起了极大的热情，期待与 ECMWF 更紧密地合作，开发对未来数值天气预报至关重要的高性能、低功耗和可扩展的计算机架构。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/view/ecmwf/across/bologna-ribbon-cutting-690px.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ECMWF 在意大利博洛尼亚开设的新数据中心将启用 Atos BullSequana 超级计算机系统，为合作提供更多机会。图片来自原文。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ACROSS 项目于 2021 年 3 月启动，将运行三年。
它旨在开发一个高性能计算、大数据和人工智能的融合平台，提供有效机制来轻松描述和管理复杂的工作流。
能源效率将发挥关键作用，大量使用专用硬件加速器、高频系统监控和应用智能作业调度机制。
该平台将由 Links 基金会 (IT)、Atos (FR)、IT4I (CZ)、Inria (FR) 和 Cini (IT) 共同设计，并将利用 &lt;a href="https://eurohpc-ju.europa.eu/"&gt;EuroHPC&lt;/a&gt; 计算资源，即 &lt;a href="https://www.cineca.it/index.php/en/hot-topics/Leonardo"&gt;CINECA Leonardo&lt;/a&gt; 和 &lt;a href="https://www.lumi-supercomputer.eu/"&gt;Lumi&lt;/a&gt; pre-exascale supercomputers 和 &lt;a href="https://www.it4i.cz/en/infrastructure/karolina"&gt;IT4I Karolina&lt;/a&gt; petascale machine。&lt;/p&gt;
&lt;p&gt;该平台将通过三个用例进行验证：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一个用例旨在通过设计一个基于机器学习的系统来探索参数化设计空间，从而提高航空涡轮机的推进效率&lt;/li&gt;
&lt;li&gt;第二个用例将面临大规模水文气象和气候工作流中的数据管理问题，解决 cloud-resolving 全球尺度数值天气预报 (NWP) 和高效后处理技术&lt;/li&gt;
&lt;li&gt;第三个用例将侧重于开发用于模拟大规模 CO2 storage 场景的系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ECMWF 与马克斯普朗克研究所 (MPI)(德国汉堡)、Deltares (NL) 和 Neuropublic (GR) 等领域专家合作，领导 ACROSS 合作伙伴开发水文气象和气候用例。&lt;/p&gt;</description></item><item><title>CMA-PI上使用Spack管理软件包</title><link>https://blog.perillaroc.wang/post/2021/12/2021-12-20-using-spack-in-cma-pi/</link><pubDate>Fri, 31 Dec 2021 16:28:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/12/2021-12-20-using-spack-in-cma-pi/</guid><description>&lt;p&gt;Spack 是一款包管理工具，支持在多种平台环境中管理多个版本。
Spack 的安装和使用均不需要管理员环境，与 Environment Modules 工具搭配，非常适合普通用户在高性能计算机 (HPC) 环境中管理自行安装的软件包。&lt;/p&gt;
&lt;p&gt;本文介绍如何在中国气象局超算 CMA-PI 上安装并使用 Spack 管理软件包。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;h3 id="联网"&gt;联网&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：Spack 安装需要连接互联网，请自行确认使用过程符合安全管理规定&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;使用工作电脑可以搭建连接互联网的代理服务，具体方法请参考《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-04-19-use-ccproxy-to-access-internet/"&gt;使用CCProxy访问互联网&lt;/a&gt;》。&lt;/p&gt;
&lt;h3 id="modules"&gt;Modules&lt;/h3&gt;
&lt;p&gt;CMA-PI 上的 Environment Modules 版本太低，不支持 spack 生成的 modulefile，建议从以下网址下载最新版本源代码并编译安装：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/cea-hpc/modules/releases/"&gt;https://github.com/cea-hpc/modules/releases/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;假设使用 bash，且安装目录为 &lt;code&gt;${PREFIX}&lt;/code&gt;，需要在 .bashrc 中加入执行初始化脚本的语句，激活新版本的 Modules：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;PREFIX&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/init/bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;下载 Spack 源码到任意目录，比如 &lt;code&gt;~/spack&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/spack/spack.git ~/spack
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：CMA-PI 上 &lt;code&gt;${HOME}&lt;/code&gt; 空间较小，建议安装在 &lt;code&gt;${WORKDIR}&lt;/code&gt; 下。
比如我将 spack 源码放到 &lt;code&gt;/g11/wangdp/spack&lt;/code&gt;，将 &lt;code&gt;${HOME}/.spack&lt;/code&gt; 指向 &lt;code&gt;/g11/wangdp/.spack&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="配置"&gt;配置&lt;/h2&gt;
&lt;p&gt;Spack 默认在临时目录中编译软件，CMA-PI 登录节点上的临时目录 &lt;code&gt;/tmp&lt;/code&gt; 空间较小，需要修改配置文件。&lt;/p&gt;
&lt;p&gt;Spack 源码中默认配置文件放在 &lt;code&gt;etc/spack/defaults/config.yaml&lt;/code&gt;，可以拷贝到 &lt;code&gt;etc/spack/config.yaml&lt;/code&gt; 创建全局配置文件。&lt;/p&gt;
&lt;p&gt;修改 &lt;code&gt;config.yaml&lt;/code&gt; 中的 build_stage 参数，比如我使用 &lt;code&gt;${WORKDIR}&lt;/code&gt; 作为临时目录：&lt;/p&gt;</description></item><item><title>2021年工作总结</title><link>https://blog.perillaroc.wang/post/2021/12/2021-12-30-2021-summary-of-working-in-cemc/</link><pubDate>Thu, 30 Dec 2021 20:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/12/2021-12-30-2021-summary-of-working-in-cemc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;为 2021 年 12 月 21 日召开的业务运行室 2021 年度工作汇报会准备的幻灯片&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大家好，我汇报下 2021 年的工作总结。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2021/summary/work/slide-01.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我的汇报分为三个部分。&lt;/p&gt;
&lt;h2 id="业务运行维护"&gt;业务运行维护&lt;/h2&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2021/summary/work/slide-02.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;首先介绍业务运行维护方面的工作。
我主要负责维护四个模式的五套业务系统。&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2021/summary/work/slide-03.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;在业务系统升级方面，今年我参与三个系统的四次业务化升级工作。&lt;/p&gt;
&lt;p&gt;在全球台风报文检索任务中，我去年开发的气象中心台风数据库检索程序今年已应用在业务系统中。
同时还集成了全球台风产品制作模块。&lt;/p&gt;
&lt;p&gt;我还完成了区域模式产品整合，使用 MESO 3 公里图片代替 MESO 10 公里图片产品，使用 TYM 数据代替 10 公里下发数据产品。&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2021/summary/work/slide-04.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;今年我还完善去年开发的业务系统绘图脚本封装工具库。&lt;/p&gt;
&lt;p&gt;业务系统绘制一幅图片需要执行多个步骤，包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;准备运行环境&lt;/li&gt;
&lt;li&gt;设置环境变量&lt;/li&gt;
&lt;li&gt;运行绘图程序&lt;/li&gt;
&lt;li&gt;执行图片图例&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个绘图脚本封装工具库依托于产品科同志编写的标准化绘图脚本，封装并整合所有这些步骤，形成统一的绘图接口，通过用户指定的参数和内置的配置文件绘制不同的图片。&lt;/p&gt;
&lt;p&gt;去年已应用在交互分析环境中，今年通过命令行程序的方式应用在高性能计算机的业务系统中，并开展基于 Docker 的容器封装研究，计划明年应用在天擎加工流水线上。&lt;/p&gt;
&lt;p&gt;今年主要工作是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更新软件架构，支持 NCL、Python 绘图脚本&lt;/li&gt;
&lt;li&gt;目前已整合 340 多幅图片&lt;/li&gt;
&lt;li&gt;已应用在 GFS 和 MESO 业务系统中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2021/summary/work/slide-05.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;今年我还参与气象信息化系统工程项目《数值预报支撑子系统》，参与公开招标、合同签订、需求分析和概要设计等流程，并为开发开展多项准备工作。&lt;/p&gt;
&lt;p&gt;通过该项目，我们计划将业务系统流程中的产品制作和产品分发任务迁移到气象大数据云平台中，在 HPC 上仅保留核心流程，简化 HPC 上的运行流程，保障模式稳定运行。&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2021/summary/work/slide-06.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;在业务系统备份方面，我参与 CMA-GFS 在北京局 HPC 上的备份工作。
完成运行环境迁移，包括ecFlow 服务和作业调度系统。
完成产品后处理系统的迁移。
目前国家局 HPC 可以直接查看北京局 HPC 上 ecFlow 系统的运行状态。&lt;/p&gt;</description></item><item><title>个人技术工作总结</title><link>https://blog.perillaroc.wang/post/2021/11/2021-11-24-summary-of-personal-technical-work/</link><pubDate>Wed, 24 Nov 2021 09:47:54 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/11/2021-11-24-summary-of-personal-technical-work/</guid><description>&lt;blockquote&gt;
&lt;p&gt;2016年7月至2021年12月的工作总结&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本人自 2016 年 7 月获聘工程师以来，&lt;strong&gt;一直从事数值预报业务系统建设、运维和模式支撑技术研发工作，是国家气象中心数值模式支撑创新团队核心成员&lt;/strong&gt;。
围绕提高数值预报业务系统运行稳定性和产品时效性，开展业务系统集成、运行监视和分布式计算等技术研发工作，参与业务运维值班。
多项研发成果已应用于数值预报业务系统和日常运维值班中，为保障业务系统持续稳定运行和模式产品及时高效生成提供技术支撑。&lt;/p&gt;
&lt;p&gt;任工程师以来主要技术工作总结如下。&lt;/p&gt;
&lt;h2 id="一研究数值预报业务系统集成技术提高模式产品制作和分发效率"&gt;一、研究数值预报业务系统集成技术，提高模式产品制作和分发效率&lt;/h2&gt;
&lt;h3 id="1优化业务系统运行流程"&gt;1.优化业务系统运行流程&lt;/h3&gt;
&lt;p&gt;负责 CMA-TYM 模式及 CMA-GFS、CMA-MESO 等模式产品后处理子系统建设维护。
完成 CMA-TYM 系统流程优化，随模式积分进度逐时效制作产品，显著提早产品分发时间。
拆分 CMA-GFS 产品制作任务，保障核心产品尽早分发。
&lt;strong&gt;以上成果已应用在业务系统中，有效提高产品制作分发效率，提升预报产品时效性。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="2研发数据查找数据并发检测等运行工具提高业务系统的灵活性和稳定性"&gt;2.研发数据查找、数据并发检测等运行工具，提高业务系统的灵活性和稳定性&lt;/h3&gt;
&lt;p&gt;业务系统输出文件在不同时间段会被保存到HPC的不同目录中，针对这一特点，研发数据查找工具，根据配置文件自动查找文件路径，使用该工具的产品后处理系统无需再关心输入数据存储位置，可以无缝实现实时业务运行和历史产品补做。
研发数据并发检测工具，使用协程技术在单一进程中并发检测多个文件的完整性，既避免单任务顺序检查因某时效文件异常导致无法检查后续文件的问题，又节省系统资源，无需同时运行多个任务。
&lt;strong&gt;上述成果已应用在 CMA-GFS、CMA-MESO、CMA-TYM 等模式产品后处理子系统中。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="3开发绘图脚本封装工具整合业务系统绘图脚本提供适合多种用途的统一接口"&gt;3.开发绘图脚本封装工具，整合业务系统绘图脚本，提供适合多种用途的统一接口&lt;/h2&gt;
&lt;p&gt;为扩展业务系统绘图脚本适用范围，开发绘图脚本封装工具包，实现统一绘图接口，支持命令行、Python 和J upyter Notebook。
该工具极大简化业务系统绘图任务脚本，&lt;strong&gt;已在C MA-GFS 和 CMA-MESO 业务系统中获得应用&lt;/strong&gt;。
基于该工具研发的容器封装技术，&lt;strong&gt;为业务系统融入气象大数据云平台提供技术支撑&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="二发展数值预报业务系统运行监视技术积极引入新技术解决业务难题保障数值预报业务系统稳定运行"&gt;二、发展数值预报业务系统运行监视技术，积极引入新技术解决业务难题，保障数值预报业务系统稳定运行&lt;/h2&gt;
&lt;h2 id="1研发移动端监视技术让运维人员可以通过手机监视系统运行情况降低运维压力提高运维效率"&gt;1.研发移动端监视技术，让运维人员可以通过手机监视系统运行情况，降低运维压力，提高运维效率&lt;/h2&gt;
&lt;p&gt;为了解决值班人员仅能通过电脑屏幕一种方式获取业务系统运行情况的难题，发展移动端监视技术，基于微信开发报警信息实时推送功能，基于云平台开发运行状态显示网页，为值班人员提供另一种监视手段。
主持开发新版业务系统运维平台，使用天镜接口保存运行数据并发送微信报警消息，实现数值预报业务与天镜平台对接。
&lt;strong&gt;以上成果已应用在业务系统日常运维值班中，有效降低值班人员的运维压力&lt;/strong&gt;。相关成果已发表1篇核心论文。&lt;/p&gt;
&lt;h3 id="2开展基于消息通信的运行监视和分析技术研发提供数据生成通知机制"&gt;2.开展基于消息通信的运行监视和分析技术研发，提供数据生成通知机制&lt;/h3&gt;
&lt;p&gt;为了向产品制作任务提供有效的数据生成通知机制，研发基于消息通讯的运行监视和分析技术，实时发送产品消息，实现标准时间统计分析算法，为运维人员提供直观的系统运行情况。
&lt;strong&gt;以上成果已应用在业务系统中，并在国家气象中心综合业务感知平台中得到应用。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="3开展运行数据分析和可视化展示技术研发为保障业务系统稳定运行提供参考数据"&gt;3.开展运行数据分析和可视化展示技术研发，为保障业务系统稳定运行提供参考数据&lt;/h2&gt;
&lt;p&gt;为了在迁移到派-曙光 HPC 过程中实现同时监控两个 HPC 平台中的业务系统，发展运行数据分析和可视化展示技术，开发派-曙光数值预报业务监控系统，研发工作流软件 ecFlow 日志分析技术。
针对模式积分时长不稳定现象，研发基于机器学习的模式积分时长预测算法，能够在积分早期发现积分耗时异常的作业。
&lt;strong&gt;以上成果已应用到业务系统日常运维值班中，为保障业务系统稳定运行提供参考数据。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="三开展分布式计算技术研究为数值预报业务应用和发展提供先进技术支撑"&gt;三、开展分布式计算技术研究，为数值预报业务应用和发展提供先进技术支撑&lt;/h2&gt;
&lt;h3 id="1开发模式数据处理工具库为使用-python-进行模式数据分析提供技术支撑"&gt;1.开发模式数据处理工具库，为使用 Python 进行模式数据分析提供技术支撑&lt;/h3&gt;
&lt;p&gt;为了提高编写 Python 数据分析代码的效率，开发数据访问与处理 Python 工具库，提供多种数据源查找访问方法，设计并实现将数据加载为常用 Python 数据结构的 API 接口。
&lt;strong&gt;该工具库已集成在GetPy软件包中。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>reki库快速上手指南</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-20-reki-quick-overview/</link><pubDate>Wed, 20 Oct 2021 13:14:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-20-reki-quick-overview/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自 &lt;a href="https://reki.readthedocs.io/"&gt;reki 文档&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/reki"&gt;reki&lt;/a&gt; (前称 nwpc-data) 是为 CMA 天气模式开发的数据访问 Python 开源工具库，提供检索要素场的便捷方法。&lt;/p&gt;
&lt;p&gt;reki 支持 GRIB、GrADS、NetCDF、CSV 等多种数据格式，对接中国气象局 CMA-PI 高性能计算机、二级存储等多种数据来源，可在 Windows、Linux 等环境中运行。 reki 提供区域截取、插值等多种数据操作方法。&lt;/p&gt;
&lt;p&gt;本文介绍 reki 库的一些常用示例。&lt;/p&gt;
&lt;p&gt;首先导入需要使用的一些库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;h3 id="依赖库"&gt;依赖库&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;reki&lt;/code&gt; 使用 eccodes 解码 GRIB 数据，请安装 ecCodes 的 Python API 接口。
推荐使用 &lt;code&gt;conda&lt;/code&gt; 安装，conda 会自动完成 ecCodes python
接口的依赖包安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conda install -c conda-forge eccodes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="安装-reki"&gt;安装 reki&lt;/h3&gt;
&lt;p&gt;从 Github 中下载最新的源代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/nwpc-oper/reki
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd reki
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;pip&lt;/code&gt; 命令安装：&lt;/p&gt;</description></item><item><title>nwpc-data更名为reki</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-16-nwpc-data-is-renamed-to-reki/</link><pubDate>Tue, 19 Oct 2021 21:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-16-nwpc-data-is-renamed-to-reki/</guid><description>&lt;p&gt;&lt;strong&gt;nwpc-data&lt;/strong&gt; 是从 2020 年 3 月开始开发的 Python 工具库，最早提供的功能是从 GRIB 2 格式数据中载入特定要素场。
开发 nwpc-data 的想法源自数值模式支撑团队讨论会，同时参考了 &lt;a href="https://github.com/nmcdev/nmc_met_io"&gt;nmcdev/nmc_met_io&lt;/a&gt; 和 &lt;a href="https://github.com/ESMValGroup/ESMValCore"&gt;ESMValCore&lt;/a&gt; 库中将数据处理与诊断算法分离的设计理念，连给库起名也在仿造 nmc_met_io。&lt;/p&gt;
&lt;p&gt;最早版本通过封装 cfgrib 库 API 接口返回 &lt;code&gt;xarray.DataArray&lt;/code&gt; 对象 (&lt;code&gt;load_field_from_file&lt;/code&gt;)。
同时也通过封装 ecCodes API 返回 ecCodes 中使用的 GRIB 消息对象 (&lt;code&gt;load_message_from_file&lt;/code&gt;)，该接口也应用在单位的 GetPy 工具中。
在开发过程中逐渐发现当时 cfgrib 版本不方便使用的地方，随后参考 cfgrib 库使用 ecCodes API 自行封装 GRIB 消息生成 &lt;code&gt;xarray.DataArray&lt;/code&gt; 对象。
虽然自行开发数据访问库远不如 cfgrib 功能完备，更新也不够频繁，但我自认为新实现的 API 接口使用更加方便，也更容易根据用户需求进行扩展。
所以今年将完善 nwpc-data 库作为个人的重点工作，也以该库为基础工具申请了单位的青年基金课题。&lt;/p&gt;
&lt;p&gt;不过不同于 nmc_met_io 等项目，nwpc-data 仅是我在工作期间开发的项目，尚未成为 NWPC 对外发布的官方开源项目。
随着 NWPC 改组为 CEMC，原有项目名称已不再合适。
虽然项目改名（尤其是 Python 库改名）会导致严重的兼容性问题，原有代码无法直接使用改名后的新版库，但最近半年我逐渐认为（个人）项目名称不宜附带单位缩写，最好寻找朗朗上口的简短名称。
比如我在前一段时间将 nwpc-graphics 改为 &lt;a href="https://github.com/nwpc-oper/sokort"&gt;sokort&lt;/a&gt;。
经过一番搜索，我决定将 nwpc-data 更名为 &lt;strong&gt;reki&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>读书笔记：基层女性</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-06-ji-ceng-nv-xing/</link><pubDate>Wed, 06 Oct 2021 23:02:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-06-ji-ceng-nv-xing/</guid><description>&lt;p&gt;本文记录 9 月最后一周在读书小组发的一篇读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基层女性 王慧玲&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/book/ji-ceng-nv-xing/douban-2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自豆瓣&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;由热门情感博主玲玲 Peter 和四只猫写的一本书，有明确的受众，显然不是我，所以读起来有些意难平。
全书透漏出作者更倾向于精致利己主义。
尽管两性话题是一个高危敏感话题，还是要通过阅读不同角度的书来接触并尝试理解不同的思潮，来锻炼自己的批判性思维。
对于赞同的地方要更深化理解，对于新学到的观点要借鉴领悟，对于逻辑有漏洞的论点要果断指出，对于不合自己三观的说法要坚决批判。
书中部分核心观点非常值得学习，比如要独立，要心智成熟，要慎重慎重对待恋爱、结婚和生育。
至于其他我不同意的观点就不敢说了，等看完《最好的决定》再仔细思考下。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/35532047/"&gt;豆瓣《基层女性》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>读书笔记：沙丘 第一部</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-06-book-dune-one/</link><pubDate>Wed, 06 Oct 2021 22:55:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-06-book-dune-one/</guid><description>&lt;p&gt;本文记录 9 月在读书小组发的两篇读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;沙丘 [美]弗兰克·赫伯特&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/book/dune-1/douban-2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自豆瓣&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;为下半年即将上映的同名电影预热，开始阅读沙丘系列小说。
相对于之前阅读的大量网络小说，沙丘的情节推进更具有跳跃性。
这部小说除了一些道具略有科幻色彩外，看不到硬核科幻元素，反而一些设定更像奇幻小说，比如宗教、传说、预言、超能力和维系超能力的特殊食物等。
开篇的故事情节也偏向宫斗，充斥各种算计和背叛。
小说的世界框架和设定是随着情节进展逐步揭示的，这也是保留悬念的一种好方法。&lt;/p&gt;
&lt;p&gt;这部科幻小说区别于我之前阅读过的国内网络小说的一个显著特点，就是宗教和预言占据核心地位。
最近刚播 2 集的科幻电视剧《基地》也有类似的设定。
小说同时也提到宗教与政治交织在一起的风险，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当宗教与政治同乘一辆马车时，驾车人会觉得没有什么东西可以阻挡它们。
他们会把一切危机意识抛诸脑后，忘记前面的悬崖并不会主动提醒闭起眼睛盲目狂奔的人。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但小说中主人公最终还是选择宗教带来统治优势，成为预言中的救世主。
很少看到国内小说这么深入地描写宗教和预言对文明的影响，可能我们中华民族一直以来都不是一神论者，也就不信所谓救世主的那一套。
读过《沙丘》发现很多网络小说都借鉴了它的写作方法，不愧是一部科幻经典作品。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/26836970/"&gt;豆瓣《沙丘》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>读书笔记：蛤蟆先生去看心理医生</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-06-book-counseling-for-toads/</link><pubDate>Wed, 06 Oct 2021 22:51:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-06-book-counseling-for-toads/</guid><description>&lt;p&gt;本文记录 8 月中旬在读书小组发的两篇读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蛤蟆先生去看心理医生 [英]罗伯特·戴博德&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/book/hama/douban-2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自豆瓣&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="1---6-章"&gt;1 - 6 章&lt;/h2&gt;
&lt;p&gt;这周读书比较少，刚看开头，讲述儿童时期形成的性格对成年的影响，也就是家庭对个人的影响，没想到心理学入门书籍还能看到育儿相关内容，争取下周读完。&lt;/p&gt;
&lt;h2 id="7---16-章"&gt;7 - 16 章&lt;/h2&gt;
&lt;p&gt;书中介绍人有三种自我状态：儿童自我状态，父母自我状态和成人自我状态。&lt;/p&gt;
&lt;p&gt;着重强调童年经历对个人心理的影响，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;从出生到大约四五岁的时候，发生的一切都对你影响重大，还影响了你后来的成长，牵涉到你怎样看待自己和别人。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对此我有两方面的理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从自身角度出发，儿童时期、家庭经历决定一生命运，仿佛成人之后只能被动接受，感觉有些宿命论的意味，不过书中也提到成人经过一番努力有可能克服少年经历改变自身性格习惯；&lt;/li&gt;
&lt;li&gt;从家长角度出发，必须注重对幼儿的教育，必须明确自己在孩子成长中扮演的角色，避免给孩子留下不可弥补的创伤。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从书中看到，成长的目标之一是更多地维持在成人自我状态，以提高对自我的认识，而这恰恰是一件非常困难的事情，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;越是能帮助你深入自我的概念，也越容易引发激烈的阻抗，&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;我们看到的自己，并不一定总是我们喜欢的样子。从当下的你，变成你想成为的自己，必定要经历行为和态度的转变，需要付出艰辛的努力，需要勇气和决心。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这本简短的心理学科普书籍，虽然讲解很生动，但没有对如何才能认识自我给出更多的解读，读后感觉自己还需要更深入地学习心理学，尤其应该阅读育儿方面的书籍。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/35143790/"&gt;豆瓣《蛤蟆先生去看心理医生》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>2021年第三季度工作总结</title><link>https://blog.perillaroc.wang/post/2021/10/2021-10-05-2021-q3-summary/</link><pubDate>Wed, 06 Oct 2021 22:42:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/10/2021-10-05-2021-q3-summary/</guid><description>&lt;blockquote&gt;
&lt;p&gt;冬天来了，春天还会远吗&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;国庆假期无法出京，连绵阴雨加上气温骤降，正是我回顾第三季度工作时心情的最佳写照。
自身心态和进取心的变化，加上单位改革的影响，让整个季度都弥漫在一种“山重水复疑无路”的氛围中。
第二季度我怀疑自己进入 35 岁魔咒期，又过了失意的三个月后，现在我完全肯定自己进入到瓶颈期。
工作之中缺乏明确的方向，而工作之外又找不到学习的动力，归根结底还是懒惰加上自我逃避。
即使我没有刻意观察，现在也能明显看到机构改革对工作气氛的影响，围绕在新中心成立问题上的各种纷争并没有随着时间而消散，却随着部门划定而越发突出。
好在我属于没有选择余地的那一批人，所以也就不用太纠结未来会怎样，已经处在链条的最底层，未来还会比现在更差么？
规划一下未来三个月过渡期的工作，静观后续就好了。&lt;/p&gt;
&lt;h2 id="计划完成情况"&gt;计划完成情况&lt;/h2&gt;
&lt;p&gt;第三季度计划任务的完成度相当惨淡：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务系统
&lt;ul&gt;
&lt;li&gt;⏰ GRAPES MESO 3KM v5.1 升级&lt;/li&gt;
&lt;li&gt;✔️ GRAPES GFS v3.2 升级&lt;/li&gt;
&lt;li&gt;⏰ GRAPES TYM 替代 GRAPES MESO 10KM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;青年基金课题项目
&lt;ul&gt;
&lt;li&gt;✔️ 研究分布式数据处理技术&lt;/li&gt;
&lt;li&gt;业务系统数据处理任务
&lt;ul&gt;
&lt;li&gt;✔️ 并行版本&lt;/li&gt;
&lt;li&gt;❌ 比较效率&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据处理工具 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;数据类型
&lt;ul&gt;
&lt;li&gt;✔️ GrADS&lt;/li&gt;
&lt;li&gt;✔️ Table&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据来源
&lt;ul&gt;
&lt;li&gt;❌ CMADaaS&lt;/li&gt;
&lt;li&gt;❌ NWPC 数据平台&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;❌ 数据操作&lt;/li&gt;
&lt;li&gt;❌ 多文件操作函数&lt;/li&gt;
&lt;li&gt;❌ MOML + CNN MOML&lt;/li&gt;
&lt;li&gt;❌ 文档&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;绘图脚本工具 &lt;a href="https://github.com/nwpc-oper/sokort"&gt;sokort&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;✔️ 在业务系统中实际应用&lt;/li&gt;
&lt;li&gt;✔️ Docker 镜像封装&lt;/li&gt;
&lt;li&gt;❌ 加工流水线&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;消息通知工具 overfor
&lt;ul&gt;
&lt;li&gt;❌ log 类型消息全流程处理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;❌ 重启工作流项目 &lt;a href="https://github.com/perillaroc/takler"&gt;takler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="业务系统"&gt;业务系统&lt;/h3&gt;
&lt;p&gt;完成 GRAPES GFS v3.2 版本升级，更新台风后处理模块，同时也将绘图脚本工具 &lt;a href="https://github.com/nwpc-oper/sokort"&gt;sokort&lt;/a&gt; 正式应用到业务系统中。&lt;/p&gt;</description></item><item><title>庆祝中国气象局地球系统数值预报中心成立</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-30-celebrate-the-establishment-cemc/</link><pubDate>Thu, 30 Sep 2021 22:47:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-30-celebrate-the-establishment-cemc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;9月30日，中国气象局地球系统数值预报中心（以下简称“数值预报中心”）成立。
这是中国气象局党组深入贯彻落实习近平总书记关于气象工作重要指示精神，对标监测精密、预报精准、服务精细要求，加快推进气象现代化建设和气象强国建设的重要举措。
中国气象局党组书记、局长庄国泰强调，数值预报是气象领域的“芯片”和“国之重器”，要举部门内外之力，大力发展我国自主可控的地球系统数值预报模式，建设我国自主培养的气象科技创新队伍，推动地球系统数值预报技术和业务高质量发展。&lt;/p&gt;
&lt;p&gt;引自 CMA 官网《中国气象局地球系统数值预报中心成立》&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.cma.gov.cn/2011xwzx/2011xqxxw/2011xqxyw/202109/t20210930_585453.html"&gt;https://www.cma.gov.cn/2011xwzx/2011xqxxw/2011xqxyw/202109/t20210930_585453.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/09/cemc-0930/cemc-20210930.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片来自中国气象公众号文章《&lt;a href="https://mp.weixin.qq.com/s/fYMk566Z8hT9J9aLo0vasw"&gt;海报 | 中国气象局地球系统数值预报中心成立了！&lt;/a&gt;》&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;热烈庆祝中国气象局地球系统数值预报中心于 2021 年 9 月 30 日成立。&lt;/p&gt;
&lt;p&gt;中国气象局地球系统数值预报中心英文名称是 Center for Earth System Modeling and Prediction of CMA (CEMC)，简称数值预报中心。
很荣幸能成为新中心的一员，略微有些遗憾的是以后向别人介绍自己工作单位时不能再说是中央气象台了。&lt;/p&gt;
&lt;p&gt;早上在中心成立大会上，局长发表了重要讲话，对后续开展工作有重大指导意义。
讲话提到新中心科研很重要，要以需求为导向，并着重强调我们的工作要以 &lt;strong&gt;提高预报准确性和预报提前量&lt;/strong&gt; 为目标。&lt;/p&gt;
&lt;p&gt;下面我就针对自己的工作职责简要谈些个人感想。&lt;/p&gt;
&lt;h2 id="工作职责"&gt;工作职责&lt;/h2&gt;
&lt;p&gt;我的工作职责与数值预报模式的业务运行紧密相连，涉及气象信息化领域，基本包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数值预报业务系统运行监控维护&lt;/li&gt;
&lt;li&gt;数值预报业务系统流程建设、优化改进&lt;/li&gt;
&lt;li&gt;数值预报模式研发支撑技术开发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上述工作均处在整个工作链条的最末端，受欢迎程度可想而知，业务运行 &lt;em&gt;似乎&lt;/em&gt; 已成为人人都不愿意碰的领域，在之前多篇博文中我已有过详尽的讨论。
虽然我不认为自己整个工作生涯都将从事上述工作，但也不能被动等待转机的出现，而应该从当前职责出发寻找突破口，认清自身，分析现状，展望未来。
因此就更应该将具体工作向中心愿景靠拢，为从事的所有工作内容编织能体现其价值的故事。&lt;/p&gt;
&lt;h2 id="预报准确性"&gt;预报准确性&lt;/h2&gt;
&lt;p&gt;数值预报业务系统最重要的指标之一就是预报准确性，这属于数值预报模式研发范畴，作为一名业务运行相关人员，很难拿出能直接提高预报准确性的工作成果。
(也许 AI 是一个方向？)&lt;/p&gt;
&lt;p&gt;不过可以从协助模式研发工作方面入手，开展模式研发支撑技术研究，提供可以提高模式研发效率的各类平台、应用和工具。
这是一项需要攻坚克难精神的工作，也是我目前在工作上的薄弱环节。
支撑技术与国外先进中心差距明显，摆在业务运行人员面前的研发方向较多，就更需要有明确可行的发展目标，扎实有效的技术路线，确定主要任务，集中精力攻关，形成有价值的工作成果，助力模式研发工作。&lt;/p&gt;
&lt;h2 id="预报提前量"&gt;预报提前量&lt;/h2&gt;
&lt;p&gt;说到提高预报提前量，第一个想法通常就是模式算得要快，也就是要研究并行计算技术，可惜不属于我的职责范畴。
不过业务运行相关人员可以从业务系统流程角度入手，在模式同化、积分等程序外围对整个业务系统进行优化改进，尤其是业务系统的流程。
比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优化业务系统搭建策略，拆分业务系统的前端和后端，从主流程中剥离观测资料检索和产品制作&lt;/li&gt;
&lt;li&gt;研究更智能的运行容错机制，自动处理常见故障，减少人为操作，降低整个系统的故障恢复时间&lt;/li&gt;
&lt;li&gt;设计更合理的运行流程，能并发运行的一律改成并发执行，降低任意故障对整个系统的影响&lt;/li&gt;
&lt;li&gt;提高资料预处理和产品制作部分的运行效率，充分利用各类计算资源，尽可能降低运行时间&lt;/li&gt;
&lt;li&gt;打通业务系统全流程，促进上下游环节各单位共同提高模式系统的运行稳定性和时效性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上部分工作我们已取得显著成效，在新单位中也将继续从各个角度出发研究如何提高业务系统的预报提前量。
我需要更加深入地投入到对业务系统的优化升级工作中，积极将研究成果、已开发工具引入到业务系统中。
不要惧怕对业务系统进行大刀阔斧的改动，只有经过试错才能找到最合适的路线。&lt;/p&gt;
&lt;h2 id="结束语"&gt;结束语&lt;/h2&gt;
&lt;p&gt;讲话中提到新中心要采取揭榜挂帅制度，采用赛马方式，也许会对当前的工作方式带来极大的冲击。
不过变革不只带来挑战，也会带来机遇。
不能将自己限制在规定动作内，要放宽眼界，开阔视野，从整个系统工程的角度出发，提高自己的各项技能。
愿我能为中国数值天气预报事业做出自己的贡献。&lt;/p&gt;</description></item><item><title>读取wgrib2变量表格</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-29-read-wgrib2-parameter-table/</link><pubDate>Wed, 29 Sep 2021 22:22:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-29-read-wgrib2-parameter-table/</guid><description>&lt;p&gt;本文将探讨 &lt;code&gt;wgrib2&lt;/code&gt; 显示的变量名从何而来。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;wgrib2&lt;/code&gt; 浏览 GRAPES GFS 的 GRIB 2 文件，会展示如下输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wgrib2 gmf.gra.2021092900003.grb2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;1:0:d=2021092900:ACPCP:surface:0-3 hour acc fcst:
2:1006387:d=2021092900:NCPCP:surface:0-3 hour acc fcst:
3:1804937:d=2021092900:APCP:surface:0-3 hour acc fcst:
4:3100143:d=2021092900:ASNOW:surface:0-3 hour acc fcst:
5:3682085:d=2021092900:TMP:surface:3 hour fcst:
6:4408726:d=2021092900:NLWRF:surface:0-3 hour acc fcst:
7:5701054:d=2021092900:NSWRF:surface:0-3 hour acc fcst:
8:6186835:d=2021092900:HFLUX:surface:3 hour fcst:
9:6935173:d=2021092900:LHTFL:surface:0-3 hour acc fcst:
10:7726184:d=2021092900:ULWRF:surface:3 hour fcst:
11:8727007:d=2021092900:ULWRF:top of atmosphere:3 hour fcst:
12:10070648:d=2021092900:var discipline=0 master_table=4 parmcat=5 parm=8:surface:3 hour fcst:
13:11037044:d=2021092900:var discipline=0 center=38 local_table=1 parmcat=5 parm=224:surface:3 hour fcst:
# ...skip...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果是一个表格，每行表示一个要素场，冒号 &lt;code&gt;:&lt;/code&gt; 为分隔符。
其中第四个字段是要素场变量名，分为两类：&lt;/p&gt;</description></item><item><title>Dask应用：计算站点风险概率预报产品</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-29-calculate-station-risk-probability-product-using-dask/</link><pubDate>Wed, 29 Sep 2021 17:18:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-29-calculate-station-risk-probability-product-using-dask/</guid><description>&lt;p&gt;本文介绍如何使用 Dask 从集合预报数据中提取数据，为站点计算风险概率预报产品。&lt;/p&gt;
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;集合预报模式的产品后处理任务比确定性模式涉及更多的数据。&lt;/p&gt;
&lt;p&gt;本文关注如何从集合预报系统输出的逐时效 GRIB 2 数据中计算某站点的概率预报产品。
即从各个成员的 GRIB 2 文件中提取相应要素的站点数据，得到一个与成员个数相同的预报值数组，根据给定阈值计算超过阈值的概率。&lt;/p&gt;
&lt;p&gt;具体需求可以浏览《智慧冬奥2022天气预报示范计划 (SMART2022-FDP) —— 技术方案》中 &lt;em&gt;4.1.6 模式集成产品&lt;/em&gt; 章节，其中表 4-12 给出影响赛事的气象风险阈值。
这里仅摘录部分产品要求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;温度：超过阈值的概率，例如 &amp;lt; 0°C，&amp;gt; 5°C 等&lt;/li&gt;
&lt;li&gt;能见度：超过阈值的概率，例如 &amp;lt; 500m，&amp;lt; 200m 等&lt;/li&gt;
&lt;li&gt;降水：超过阈值的概率，例如 &amp;gt; 1mm，&amp;gt; 2mm 等&lt;/li&gt;
&lt;li&gt;平均风速：超过阈值的概率，例如 &amp;gt; 4m/s，&amp;gt; 10m/s 等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="现有方案"&gt;现有方案&lt;/h2&gt;
&lt;p&gt;NWPC 正在建设的产品后处理系统中采用串行方式生成风险概率预报产品。
利用 &lt;code&gt;wgrib2&lt;/code&gt; 提取需要的数据，再由 NWPC 内部开发的 &lt;code&gt;smartFDP_meps.exe&lt;/code&gt; 程序计算概率值，最后通过 &lt;code&gt;sed&lt;/code&gt; 等 Linux 命令行工具生成 XML 文件。
具体过程如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data-process/winter/ens-station/winter-ens-station-serial.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;单个时效的计算流程可以分为三个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据处理&lt;/strong&gt;：生成计算概率值需要的数据&lt;/p&gt;
&lt;p&gt;1.1 使用 &lt;code&gt;wgrib2&lt;/code&gt; 从所有集合成员 (m00 - m14) 的 GRIB 2 数据中将需要的变量提取并合并到单个文件中，例如将 2 米温度数据提取到 T2M.grib2 文件中，将 10 米风数据提取到 U10M.grib2 和 V10M.grib2 文件中；&lt;/p&gt;</description></item><item><title>从GrADS文件中加载要素场</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-28-nwpc-data-read-grads-binary-data/</link><pubDate>Tue, 28 Sep 2021 16:21:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-28-nwpc-data-read-grads-binary-data/</guid><description>&lt;p&gt;本文介绍如何使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库从 GrADS 格点二进制数据文件中加载单个要素场。&lt;/p&gt;
&lt;h2 id="api"&gt;API&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nwpc_data.format.grads.load_field_from_file()&lt;/code&gt; 函数用于从 GrADS 格点数据文件中加载要素场。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;load_field_from_file&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path: Union[str, Path],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter: str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type: str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level: Union[int, float, List] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_dim: Optional[str] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; latitude_direction: str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;degree_north&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time: Union[str, pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;kwargs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; Optional[xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="参数"&gt;参数&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;parameter&lt;/strong&gt;：要素名&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;level_type&lt;/strong&gt; 与 &lt;strong&gt;level&lt;/strong&gt;：层次类型和层次值&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;level_type&lt;/code&gt; 为 &lt;code&gt;pl&lt;/code&gt; 或 &lt;code&gt;ml&lt;/code&gt;，表示气压层或模式层，&lt;code&gt;level&lt;/code&gt; 为层次数值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;level_type&lt;/code&gt; 为 &lt;code&gt;single&lt;/code&gt;，表示单层变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;level_type&lt;/code&gt; 为 &lt;code&gt;index&lt;/code&gt;，表示按层次序号索引，&lt;code&gt;level&lt;/code&gt; 为层次序号，从 0 开始&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;latitude_direction&lt;/strong&gt;：纬度方向，默认从北到南 (&lt;code&gt;degree_north&lt;/code&gt;)，与 NWPC 的 GRIB 2 数据保持一致&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;forecast_time&lt;/strong&gt;：预报时效，用于单个数据描述文件对应多个单时效数据文件的情况，例如 GRAPES TYM&lt;/p&gt;
&lt;h3 id="返回值"&gt;返回值&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;xarray.DataArray&lt;/code&gt; 对象二维格点数组，与 nwpc-data 库 GRIB 2 系列 API 返回的 &lt;code&gt;DataArray&lt;/code&gt; 对象有相同的坐标：&lt;/p&gt;</description></item><item><title>Dask应用：批量转换GRIB2文件中的要素场</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-27-convert-all-message-in-a-grib2-file-using-dask/</link><pubDate>Tue, 28 Sep 2021 09:28:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-27-convert-all-message-in-a-grib2-file-using-dask/</guid><description>&lt;p&gt;本文介绍如何编写 Dask 程序实现对 GRIB 2 文件中的所有要素场进行批量转换。&lt;/p&gt;
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;对数值预报模式生成的 GRIB 2 数据文件进行再加工是数值预报产品后处理系统最常见的任务。
目前 NWPC 生成的很多产品都是对原始 GRIB 2 数据文件中的所有要素场进行批量转换，生成新的 GRIB 2 文件。
例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GRAPES GFS 东北半球产品 (grib2-ne)：裁剪区域&lt;/li&gt;
&lt;li&gt;GRAPES TYM 陕西气象局产品 (grib2-shaanxi)：裁剪区域&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类数据产品需要保证新生成文件的要素场排序与原始文件相同。&lt;/p&gt;
&lt;p&gt;下面首先介绍目前 NWPC 业务系统中使用的两种 GRIB 2 要素场批量处理方案，然后介绍如何使用 Dask 实现并发处理。&lt;/p&gt;
&lt;h2 id="现有方案"&gt;现有方案&lt;/h2&gt;
&lt;p&gt;目前 NWPC 在对单个 GRIB 2 文件中所有 GRIB 2 消息进行批量转换时使用两种串行程序：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NWPC 内部程序 &lt;code&gt;grib_post&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wgrib2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="grib_post"&gt;grib_post&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;grib_post.exe&lt;/code&gt; 是 NWPC 开发的内部程序。下面代码来自 GRAPES GFS 产品后处理系统中制作 grib2-ne 产品的脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./gribpost.exe -s &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;ORIG_DIR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/gmf.gra.&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;start_time&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;forecast_hour&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;.grb2 | &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ./gribpost.exe -i &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;ORIG_DIR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/gmf.gra.&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;start_time&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;forecast_hour&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;.grb2 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -domain &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;NLAT&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;SLAT&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;WLON&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;ELON&lt;span style="color:#e6db74"&gt;}&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -dx 0.25 -dy 0.25 -nx &lt;span style="color:#ae81ff"&gt;721&lt;/span&gt; -ny &lt;span style="color:#ae81ff"&gt;360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -grib2 ./ne_gmf.gra.&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;start_time&lt;span style="color:#e6db74"&gt;}${&lt;/span&gt;forecast_hour&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;.grb2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该程序逐个转换 GRIB 2 要素场，生成 grib2-ne 的单个时效产品耗时 6 - 7 分钟。&lt;/p&gt;</description></item><item><title>GO模板中使用函数</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-25-go-template-with-function/</link><pubDate>Sun, 26 Sep 2021 15:42:09 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-25-go-template-with-function/</guid><description>&lt;p&gt;数据路径查找工具 &lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-oper/nwpc-data-client&lt;/a&gt; 配置文件中文件名和路径名使用 GO 语言内置模板库 text/template 进行变量替换。&lt;/p&gt;
&lt;h2 id="变量替换"&gt;变量替换&lt;/h2&gt;
&lt;p&gt;例如下面是 modelvar 二进制文件名的模板，其中 &lt;code&gt;.Year&lt;/code&gt;，&lt;code&gt;.Month&lt;/code&gt;，&lt;code&gt;.Day&lt;/code&gt;，&lt;code&gt;.Hour&lt;/code&gt; 和 &lt;code&gt;.Forecast&lt;/code&gt; 表示需要替换的变量。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：text/template 默认的模板元素分隔符是 &lt;code&gt;{{ }}&lt;/code&gt;，项目通过 &lt;code&gt;Delims&lt;/code&gt; 函数修改为 &lt;code&gt;{ }&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;file_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;modelvar{.Year}{.Month}{.Day}{.Hour}_{.Forecast}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="预设变量"&gt;预设变量&lt;/h2&gt;
&lt;p&gt;GRAPES GFS 模式中文件保存为整点时次减 3 小时，即为同化时间窗起始时间。
当前业务系统使用的 nwpc-data-client 版本采用定义预设变量的方式支持 -3 小时时间。&lt;/p&gt;
&lt;p&gt;下面路径模板中 &lt;code&gt;.Year4DV&lt;/code&gt;，&lt;code&gt;.Month4DV&lt;/code&gt;，&lt;code&gt;.Day4DV&lt;/code&gt;，&lt;code&gt;.Hour4DV&lt;/code&gt; 是预设变量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GDA/Prod-grib/{.Year4DV}{.Month4DV}{.Day4DV}{.Hour4DV}/ORIG&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;预设变量在程序内部预先生成，下面代码包含两组预设变量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;4DV&lt;/code&gt;：GRAPES GFS 使用的 -3 小时&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1HR&lt;/code&gt;：GRAPES MESO 使用的 -1 小时&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;forecastHour&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; int(&lt;span style="color:#a6e22e"&gt;forecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;startTime4DV&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hour&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;startTime1HR&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hour&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tpVariable&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TimeTemplateVariable&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;StartTime&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Year&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;2006&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Month&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;01&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Day&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;02&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Hour&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;15&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Forecast&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%03d&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;forecastHour&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Year4DV&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime4DV&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;2006&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Month4DV&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime4DV&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;01&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Day4DV&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime4DV&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;02&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Hour4DV&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime4DV&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;15&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Year1HR&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime1HR&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;2006&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Month1HR&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime1HR&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;01&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Day1HR&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime1HR&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;02&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Hour1HR&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;startTime1HR&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;15&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Forecast1HR&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%03d&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;forecastHour&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用函数"&gt;使用函数&lt;/h2&gt;
&lt;p&gt;预设变量简单明了，但不利于扩展，新增时间参数需要修改源代码，无法在配置文件中直接使用。
既然上述两组预设变量生成方式几乎相同，可以创建模板函数实现动态计算。&lt;/p&gt;</description></item><item><title>Dask应用：从多个文件中抽取GRIB2要素场</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-18-extract-and-combine-grib2-message-using-dask/</link><pubDate>Sat, 25 Sep 2021 12:12:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-18-extract-and-combine-grib2-message-using-dask/</guid><description>&lt;p&gt;本文介绍如何使用 Dask 从多个文件中并发抽取 GRIB2 要素场，按顺序合并成一个文件。&lt;/p&gt;
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;GRAPES MESO 1KM 模式系统是面向 2022 北京冬奥会的业务系统，覆盖京津冀地区，每天运行 8 次，每次预报 24 小时。
与其他 GRAPES 系列模式一样，1KM 模式也逐时效生成原始 GRIB 2 数据产品 (grib2-orig)，每个文件包含单个时效的所有要素场。&lt;/p&gt;
&lt;p&gt;1KM 模式系统为冬奥会 FDP 项目生成 GRIB 2 格式的次公里网格产品 (grib2-bth)，按要素分为多个文件，每个文件包含全部 25 个预报时效。
从 grib2-orig 制作 grib2-bth 产品需要从多个文件中抽取某个特定要素场，并将这些要素场按时效顺序保存为一个文件，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data-process/winter/bth/winter-bth-introduction.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;从原始 GRIB 2 数据生成 GRIB2-BTH 产品示意图，从每个单时效文件中抽取一个要素场合并成一个时间序列文件&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="方案"&gt;方案&lt;/h2&gt;
&lt;p&gt;本文使用 Dask 同时从多时效文件中并发抽取所有要素，并按照时效顺序分别将各要素写入到单独的文件中。
算法如下所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data-process/winter/bth/winter-bth-dask.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;从多文件并发抽取 GRIB 2 并写入到新文件中，每个没有依赖关系的 Dask 任务都可以并发执行&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;下面以目前在 GRAPES MESO 1KM 业务系统中实际使用的脚本为例说明上述算法如何实现。&lt;/p&gt;
&lt;h3 id="要素筛选条件"&gt;要素筛选条件&lt;/h3&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库从 GRIB 2 文件中抽取要素场。&lt;/p&gt;</description></item><item><title>在Slurm中使用Dask</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-13-use-dask-in-slurm/</link><pubDate>Mon, 13 Sep 2021 16:14:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-13-use-dask-in-slurm/</guid><description>&lt;p&gt;本文介绍如何在中国气象局高性能计算机 CMA-PI 的并行节点中运行 Dask 程序。&lt;/p&gt;
&lt;h2 id="准备环境"&gt;准备环境&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://mpi.dask.org/en/latest/"&gt;dask-mpi&lt;/a&gt; 库支持在诸如 Slurm 等 MPI 环境中部署 Dask 负载。&lt;/p&gt;
&lt;p&gt;CMA-PI 上的 Python 环境尚未安装 dask-mpi 库。
我使用自己安装的 Anaconda 环境，通过代理在线安装 dask-mpi 库。
HPC 用户安装 Python 的具体方法请参考文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-04-22-user-level-python-for-hpc/"&gt;HPC用户安装Python解决方案&lt;/a&gt;》。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：未来可以连接 HPC 的工作电脑将无法访问互联网，上述文章中的部分方法将无法使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="python-脚本"&gt;Python 脚本&lt;/h2&gt;
&lt;p&gt;初始化 MPI 环境仅需要一行语句。注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMA-PI 使用 Infiniband 网卡，需要将 &lt;code&gt;interface&lt;/code&gt; 参数设置为 IB 网卡名 &lt;code&gt;&amp;quot;ib0&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;并行节点与外界不连通，无需启动面板，可以用 &lt;code&gt;dashboard=False&lt;/code&gt; 关闭面板&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask_mpi &lt;span style="color:#f92672"&gt;import&lt;/span&gt; initialize
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;initialize(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interface&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ib0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dashboard&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后续与原有脚本相同，比如创建 Dask 客户端：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask.distributed &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Client
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Client()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="运行脚本"&gt;运行脚本&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;mpirun&lt;/code&gt; 运行脚本，类似如下语句&lt;/p&gt;</description></item><item><title>报告阅读：如何构建促进计算机领域创新发展的学术评价体系</title><link>https://blog.perillaroc.wang/post/2021/09/2021-09-02-report-read-academic-evaluation-in-computer/</link><pubDate>Thu, 02 Sep 2021 22:53:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/09/2021-09-02-report-read-academic-evaluation-in-computer/</guid><description>&lt;p&gt;今天看到《中国计算机学会通讯》2021 年第 8 期中关于计算机领域学术评价体系的系列报告文章。
气象领域与计算机领域的评价体系不一定完全一致，但还是有一些共通之处。
我正在从事的气象信息化工作也面临这组报告提到的一些问题，而报告给出的部分建议同样也适合当前的岗位。
从讨论中可以看到未来评价机制变化的方向，可以指导未来的工作方向。&lt;/p&gt;
&lt;p&gt;报告背景，引自通讯原文&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;《关于完善科技成果评价机制的指导意见》对优化我国科技成果评价机制产生了重要影响。受此指导意见的激励和影响，CCF YOCSEF于7月22日举行闭门论坛，研讨如何构建促进计算机领域创新发展的学术评价体系。本次闭门论坛为期1天，上午总体讨论，下午分为3个小组，根据计算机领域的特点，分别从科研人员评价、科技成果评价与中长期科技评价机制三个议题进行深度思辨，形成总体篇（本篇）、科研人员评价篇、科技成果评价篇和中长期科技评价机制篇共4篇报告。此4篇报告是闭门论坛的产出，意在抛出观点，引起同行广泛关注，共同完善计算机学科评价体系。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;报告共有 4 篇，分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《&lt;a href="https://dl.ccf.org.cn/article/articleDetail.html?_ack=1&amp;amp;id=5573767860373504"&gt;构建新时代计算机领域创新发展学术评价体系&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://dl.ccf.org.cn/article/articleDetail.html?_ack=1&amp;amp;id=5573769713371136"&gt;计算机科研人员的评价体系&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://dl.ccf.org.cn/article/articleDetail.html?_ack=1&amp;amp;id=5573771680679936"&gt;计算机领域科技成果评价体系&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://dl.ccf.org.cn/article/articleDetail.html?_ack=1&amp;amp;id=5573773161351168"&gt;计算机领域中长期科技评价机制&lt;/a&gt;》&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="报告内容简述"&gt;报告内容简述&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;摘取自报告原文，根据笔者理解有所修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现行计算机领域学术评价聚焦：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;科技成果：主要包括论文、专著、专利、软件著作、标准、教材等&lt;/li&gt;
&lt;li&gt;科技活动：主要考查在科研项目、科研平台（如各类国家或部级实验室）的参与情况&lt;/li&gt;
&lt;li&gt;科研获奖情况&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;尚未纳入考虑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;科研工具开发&lt;/li&gt;
&lt;li&gt;数据集生成和整理&lt;/li&gt;
&lt;li&gt;开源贡献&lt;/li&gt;
&lt;li&gt;科普著作&lt;/li&gt;
&lt;li&gt;对诸如国家发展规划或指南等政策指导性文件的贡献&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随着研究方向的日益细化和收敛，现行评价体系在相关研究工作是否真正根本性地解决学术或工程问题上，难以做出有效甄别。
在评价指标上也存在“一刀切”问题，客观指标太多，同行主观评价占比太低，缺乏对共性和影响效果的评价。&lt;/p&gt;
&lt;p&gt;构建促进计算机领域创新发展的学术评价体系需遵循的主要原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;坚持质量、绩效、贡献为核心评价导向&lt;/li&gt;
&lt;li&gt;坚持以企业为创新主体、多元评价为导向&lt;/li&gt;
&lt;li&gt;坚持客观指标和同行评价相结合&lt;/li&gt;
&lt;li&gt;坚持短期评价和中长期评价相结合&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;科技成果的类型和形式：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/read/report/computer-202108/computer-index.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;科技成果类型、成果形式、影响方面和评价方式简表，图片来自原文&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="讨论"&gt;讨论&lt;/h2&gt;
&lt;p&gt;目前从事的工作类似于报告中提到的支撑性研发工作，文中给出 4 类工作内容，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;研发科研工具&lt;/li&gt;
&lt;li&gt;搭建基准平台&lt;/li&gt;
&lt;li&gt;制作科研数据集&lt;/li&gt;
&lt;li&gt;开源科研成果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这 4 项基本涵盖与模式研发支撑技术研发相关的所有工作。
对于每一类工作，都可以思考自己能从哪些方面入手开展研发工作，梳理已有工作，分析未来可行的道路，并做出选择。&lt;/p&gt;
&lt;p&gt;我一直在频繁切换研究方向，导致工作多年没有核心成果，后面再如此下去，就只能一直挂个 &lt;em&gt;业务运维&lt;/em&gt; 标签了。
对于需要中长期才能做出成果的任务，要有恒心和毅力。
是时候思考下未来的路该怎么走了。&lt;/p&gt;</description></item><item><title>论文阅读：收集监控分析超算中心的设施和系统数据</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-17-paper-bautista-2019-omni/</link><pubDate>Mon, 23 Aug 2021 21:49:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-17-paper-bautista-2019-omni/</guid><description>&lt;p&gt;Collecting, Monitoring, and Analyzing Facility and Systems Data at the National Energy Research Scientific Computing Center&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Elizabeth Bautista, Melissa Romanus, Thomas Davis, Cary Whitney, and Theodore Kubaska. 2019. Collecting, Monitoring, and Analyzing Facility and Systems Data at the National Energy Research Scientific Computing Center. In Proceedings of the 48th International Conference on Parallel Processing: Workshops (ICPP 2019). Association for Computing Machinery, New York, NY, USA, Article 10, 1–9. DOI: &lt;a href="https://doi.org/10.1145/3339186.3339213"&gt;https://doi.org/10.1145/3339186.3339213&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文发表于 ICPP 2019 会议，介绍 NERSC 超算中心如何收集、监控、分析设施和系统的运行数据。&lt;/p&gt;</description></item><item><title>Dask教程系列文章</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial/</link><pubDate>Sun, 22 Aug 2021 16:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial/</guid><description>&lt;p&gt;本系列文章翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目，翻译于 2021 年 8 月，版本是 2021 年 4 月 8 日提交的 &lt;a href="https://github.com/dask/dask-tutorial/tree/7f92a5a18d85a903327169e5dafb2b785021b6aa"&gt;7f92a5a18d85a903327169e5dafb2b785021b6aa&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;包括以下章节：&lt;/p&gt;
&lt;p&gt;0.&lt;a href="https://blog.perillaroc.wang/post/2021/07/2021-07-10-dask-tutorial-overview/"&gt;简介&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-07-dask-tutorial-dask-delayed/"&gt;dask.delayed&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1x.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-08-dask-tutorial-lazy/"&gt;延迟执行&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-17-dask-tutorial-bag/"&gt;Bag&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;3.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-19-dask-tutorial-array/"&gt;Array&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;4.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-20-dask-tutorial-dataframe/"&gt;DataFrame&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;5.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-distributed/"&gt;分布式&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;6.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-distributed-advanced/"&gt;分布式，高级&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;7.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-dataframe-storage/"&gt;数据存储&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;8.&lt;a href="https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-machine-learning/"&gt;并行和分布式机器学习&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Dask教程：并行和分布式机器学习</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-machine-learning/</link><pubDate>Sun, 22 Aug 2021 14:03:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-machine-learning/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://ml.dask.org/index.html"&gt;Dask-ML&lt;/a&gt; 包含用于并行和分布式机器学习的资源。&lt;/p&gt;
&lt;h2 id="伸缩类型"&gt;伸缩类型&lt;/h2&gt;
&lt;p&gt;Types of scaling&lt;/p&gt;
&lt;p&gt;您可能会面临几个明显的伸缩问题。
伸缩策略取决于您面临的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU-Bound：数据适合 RAM，但训练时间太长。许多超参数组合，许多模型的大型集成等。&lt;/li&gt;
&lt;li&gt;内存限制：数据大于 RAM，并且采样不是一种选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/dask/toturial/ml/dimensions_of_scale.png" alt=""&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于 in-memory 问题，只需使用 scikit-learn (或您最喜欢的 ML 库)。&lt;/li&gt;
&lt;li&gt;对于大型模型，请使用 &lt;code&gt;dask_ml.joblib&lt;/code&gt; 和您最喜欢的 scikit-learn estimator&lt;/li&gt;
&lt;li&gt;对于大型数据集，使用 &lt;code&gt;dask_ml&lt;/code&gt; estimator&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-分钟学会-scikit-learn"&gt;5 分钟“学会” Scikit-Learn&lt;/h2&gt;
&lt;p&gt;Scikit-Learn 有很好的、一致的 API。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实例化一个 &lt;code&gt;Estimator&lt;/code&gt; (例如 &lt;code&gt;LinearRegression&lt;/code&gt;、&lt;code&gt;RandomForestClassifier&lt;/code&gt; 等)。
所有模型 &lt;em&gt;超参数&lt;/em&gt; (用户指定的参数，不是估计器学习的参数) 在创建时都会传递给估计器。&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;estimator.fit(X, y)&lt;/code&gt; 来训练估计器。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;estimator&lt;/code&gt; 检查属性、进行预测等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;让我们生成一些随机数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sklearn.datasets &lt;span style="color:#f92672"&gt;import&lt;/span&gt; make_classification
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X, y &lt;span style="color:#f92672"&gt;=&lt;/span&gt; make_classification(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n_samples&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n_features&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; random_state&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;X[:&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([[ 1.27815198, -0.41644753, 0.89181112, 0.77129444],
 [ 1.35681817, -1.51465569, 1.82132242, 0.42081175],
 [ 1.53341056, 2.06290707, -1.01967188, 1.87609016],
 [ 0.42064934, 0.05455201, 0.13725671, 0.32493018],
 [-0.88825673, -1.10088618, 0.51393811, -1.05185003],
 [ 0.26413558, -0.42774504, 0.46291997, 0.0326177 ],
 [-1.15189334, -1.43613997, 0.6734141 , -1.36719829],
 [ 0.85289242, -0.74009387, 0.97199307, 0.34318408]])
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y[:&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([1, 1, 1, 1, 0, 1, 0, 1])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们训练一个支持向量机分类器&lt;/p&gt;</description></item><item><title>Dask教程：数据存储</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-dataframe-storage/</link><pubDate>Sun, 22 Aug 2021 12:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-dataframe-storage/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;高效的存储可以显着提高性能，尤其是在从磁盘重复操作时。&lt;/p&gt;
&lt;p&gt;解压文本和解析 CSV 文件的成本很高。
处理中等数据的最有效策略之一是使用二进制存储格式，如 HDF5。
通常这样做的性能提升就足够了，因此您可以再次切换回使用 Pandas 而不是使用 &lt;code&gt;dask.dataframe&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在本节中，我们将学习如何以磁盘上的二进制格式有效地排列和存储数据集。
我们将使用以下内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于 HDF5 的 Pandas &lt;code&gt;HDFStore&lt;/code&gt; 格式&lt;/li&gt;
&lt;li&gt;用于以数字方式存储文本数据的分类&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主要要点&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储格式影响性能一个数量级&lt;/li&gt;
&lt;li&gt;文本数据即使是像 HDF5 这样的快速格式也会保持缓慢&lt;/li&gt;
&lt;li&gt;二进制格式、列存储和分区数据的组合将一秒的等待时间变成了 80 毫秒的等待时间&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="创建数据"&gt;创建数据&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;%run prep.py -d accounts
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="读取-csv"&gt;读取 CSV&lt;/h2&gt;
&lt;p&gt;首先，我们像以前一样读取我们的 csv 数据。&lt;/p&gt;
&lt;p&gt;CSV 和其他基于文本的文件格式是许多来源数据的最常见存储方式，因为它们需要最少的预处理，可以逐行写入并且是人类可读的。
由于 Pandas 的 &lt;code&gt;read_csv&lt;/code&gt; 得到了很好的优化，CSV 是一个合理的输入，但远未优化，因为读取需要大量的文本解析。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pathlib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Path
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;filename &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Path(&lt;span style="color:#e6db74"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;accounts.*.csv&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;filename
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;WindowsPath(&amp;#39;data/accounts.*.csv&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; dask.dataframe &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; dd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_csv &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_csv(filename)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_csv&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/dask/tutorial/dataframe-storage/pic-01.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="写入到-hdf5"&gt;写入到 HDF5&lt;/h3&gt;
&lt;p&gt;HDF5 和 netCDF 是科学领域中非常常用的二进制数组格式。&lt;/p&gt;
&lt;p&gt;Pandas 包含专门的 HDF5 格式 &lt;code&gt;HDFStore&lt;/code&gt;。
&lt;code&gt;dd.DataFrame.to_hdf&lt;/code&gt; 方法与 &lt;code&gt;pd.DataFrame.to_hdf&lt;/code&gt; 方法完全一样。&lt;/p&gt;</description></item><item><title>Dask教程：分布式，高级</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-distributed-advanced/</link><pubDate>Sun, 22 Aug 2021 11:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-distributed-advanced/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="分布式-futures"&gt;分布式 futures&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask.distributed &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Client
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Client(n_workers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cluster
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/dask/tutorial/distributed-advanced/pic-01.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;在前一章中，我们展示了使用分布式执行器执行计算 (使用 &lt;code&gt;delayed&lt;/code&gt; 创建) 与任何其他执行器相同。
但是，我们现在可以访问其他功能，并控制内存中保存的数据。&lt;/p&gt;
&lt;p&gt;首先，&lt;code&gt;futures&lt;/code&gt; 接口 (源自内置的 &lt;code&gt;concurrent.futures&lt;/code&gt;) 允许类似 map-reduce 的功能。
我们可以使用一组输入提交单个函数进行评估，或者使用 &lt;code&gt;submit()&lt;/code&gt; 和 &lt;code&gt;map()&lt;/code&gt; 对一系列输入进行评估。
请注意，调用立即返回，给出一个或多个 &lt;em&gt;futures&lt;/em&gt;，其状态从 &amp;ldquo;pending&amp;rdquo; 开始，然后变为 &amp;ldquo;finished&amp;rdquo;。
没有阻塞本地 Python 会话。&lt;/p&gt;
&lt;p&gt;这是 &lt;code&gt;submit&lt;/code&gt; 操作的最简单示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;inc&lt;/span&gt;(x):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fut &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;submit(inc, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fut
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Future: inc status: pending, type: None, key: inc-c5c7b9feb85235b658578a98acc14b70
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们可以根据需要随时重新执行以下单元格，作为轮询 future 状态的一种方式。
这当然可以在循环中完成，在每次迭代时暂停一小段时间。
我们可以继续我们的工作，或者查看仍在进行的工作进度条，或者强制等待，直到未来准备就绪。&lt;/p&gt;
&lt;p&gt;与此同时，状态仪表板 (上面的集群小部件旁边的链接) 在任务流中获得了一个新元素，表明 &lt;code&gt;inc()&lt;/code&gt; 已完成，问题处的进度部分显示一个任务已完成并保存在内存中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fut
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Future: inc status: finished, type: builtins.int, key: inc-c5c7b9feb85235b658578a98acc14b70
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;您可以查看进度的可能替代方案：&lt;/p&gt;</description></item><item><title>Dask教程：分布式</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-distributed/</link><pubDate>Sun, 22 Aug 2021 10:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-22-dask-tutorial-distributed/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;到目前为止，我们已经看到，Dask 允许您简单地构建具有依赖关系的任务图，以及在数据集合上使用函数式、Numpy 或 Pandas 语法为您自动创建图。
如果没有以并行和内存感知方式执行这些图的方法，那么这些都不会非常有用。
到目前为止，我们一直在调用 &lt;code&gt;thing.compute()&lt;/code&gt; 或 &lt;code&gt;dask.compute(thing)&lt;/code&gt; 而不必担心这意味着什么。
现在我们将讨论可用于该执行的选项，特别是带有附加功能的分布式调度器。&lt;/p&gt;
&lt;p&gt;Dask 带有四个可用的调度器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;&lt;strong&gt;threaded&lt;/strong&gt;&amp;rdquo; (aka &amp;ldquo;&lt;strong&gt;threading&lt;/strong&gt;&amp;quot;)：由线程池支持的调度器&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;strong&gt;processes&lt;/strong&gt;&amp;quot;：由进程池支持的调度器&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;strong&gt;single-threaded&lt;/strong&gt;&amp;rdquo; (aka &amp;ldquo;&lt;strong&gt;sync&lt;/strong&gt;&amp;quot;)：同步调度器，适合调试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;distributed&lt;/strong&gt;：用于在多台机器上执行图的分布式调度器，见下文&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;要选择其中之一进行计算，您可以在请求结果时指定，例如，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;myvalue&lt;span style="color:#f92672"&gt;.&lt;/span&gt;compute(scheduler&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;single-threaded&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# 用于调试&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;您也可以临时设置默认调度器&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; dask&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(scheduler&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;processes&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 仅临时为本代码块设置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 本代码块中所有的计算请求将使用指定的调度器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myvalue&lt;span style="color:#f92672"&gt;.&lt;/span&gt;compute()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; anothervalue&lt;span style="color:#f92672"&gt;.&lt;/span&gt;compute()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者全局设置&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 设置直至另行通知&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dask&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(scheduler&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;processes&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;让我们在熟悉的航班数据案例上尝试一些调度器。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;%run prep.py -d flights
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="构建计算图"&gt;构建计算图&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; dask.dataframe &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; dd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pathlib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Path
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_csv(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Path(&lt;span style="color:#e6db74"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;nycflights&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;*.csv&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parse_dates&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Date&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dtype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;TailNum&amp;#34;&lt;/span&gt;: object,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;CRSElapsedTime&amp;#34;&lt;/span&gt;: float,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Cancelled&amp;#34;&lt;/span&gt;: bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 按机场分组的最大平均未取消延误&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;largest_delay &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#f92672"&gt;~&lt;/span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Cancelled]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;groupby(&lt;span style="color:#e6db74"&gt;&amp;#34;Origin&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DepDelay&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mean()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;largest_delay
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;dd.Scalar&amp;lt;series-..., dtype=float64&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;largest_delay&lt;span style="color:#f92672"&gt;.&lt;/span&gt;visualize(optimize_graph&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/dask/tutorial/distributed/pic-01.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>Dask教程：DataFrames</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-20-dask-tutorial-dataframe/</link><pubDate>Fri, 20 Aug 2021 22:14:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-20-dask-tutorial-dataframe/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们通过使用 &lt;code&gt;dask.delayed&lt;/code&gt; 在 CSV 文件目录上构建并行数据框计算来完成章节 1。
在本节中，我们使用 &lt;code&gt;dask.dataframe&lt;/code&gt; 自动构建类似的计算，用于表格计算的常见情况。
Dask 数据框的外观和感觉就像 Pandas 数据框，但它们运行在支持 &lt;code&gt;dask.delayed&lt;/code&gt; 的相同基础架构上。&lt;/p&gt;
&lt;p&gt;在这个笔记本中，我们使用与以前相同的航空公司数据，但现在我们让 &lt;code&gt;dask.dataframe&lt;/code&gt; 为我们构建计算，而不是编写 &lt;code&gt;for&lt;/code&gt; 循环。
&lt;code&gt;dask.dataframe.read_csv&lt;/code&gt; 函数可以采用像 &lt;code&gt;&amp;quot;data/nycflights/*.csv&amp;quot;&lt;/code&gt; 这样的匹配字符串，并一次对我们所有的数据进行并行计算。&lt;/p&gt;
&lt;h2 id="什么时候使用-daskdataframe"&gt;什么时候使用 &lt;code&gt;dask.dataframe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Pandas 适用于适合内存的表格数据集。
当您要分析的数据集大于机器的 RAM 时，Dask 会变得很有用。
我们正在使用的演示数据集只有大约 200 MB，因此您可以在合理的时间内下载它，但 &lt;code&gt;dask.dataframe&lt;/code&gt; 将扩展到比内存大得多的数据集。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dask.dataframe&lt;/code&gt; 模块实现了一个分块并行 &lt;code&gt;DataFrame&lt;/code&gt; 对象，它模仿了 Pandas &lt;code&gt;DataFrame&lt;/code&gt; API 的一个很大的子集。
一个 Dask &lt;code&gt;DataFrame&lt;/code&gt; 由许多沿索引分隔的在内存中的 Pandas &lt;code&gt;DataFrame&lt;/code&gt; 组成。
Dask &lt;code&gt;DataFrame&lt;/code&gt; 上的一个操作会以一种注意潜在并行性和内存限制的方式触发对组成 Pandas &lt;code&gt;DataFrame&lt;/code&gt; 的许多 Pandas 操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相关文档&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/dataframe.html"&gt;DataFrame documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/AT2XtFehFSQ"&gt;DataFrame screencast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/dataframe-api.html"&gt;DataFrame API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://examples.dask.org/dataframe.html"&gt;DataFrame examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pandas.pydata.org/pandas-docs/stable/"&gt;Pandas documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;主要卖点&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Dask教程：数组</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-19-dask-tutorial-array/</link><pubDate>Thu, 19 Aug 2021 22:08:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-19-dask-tutorial-array/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dask 数组使用阻塞算法提供并行，大于内存，N维的数组。
简单地说：分布式 Numpy。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/dask/tutorial/array/array.png" alt=""&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;并行 (Parallel)&lt;/strong&gt;：使用计算机的所有核&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大于内存 (Larger-than-memory)&lt;/strong&gt;：通过将数组分解成许多小块，按顺序对这些块进行操作以最大限度地减少计算的内存占用，并有效地从磁盘流式传输数据，让您可以处理大于可用内存的数据集&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分块算法 (Blocked Algorithms)&lt;/strong&gt;：通过执行许多较小的计算来执行大型计算&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在本笔记本中，我们将通过从头开始实现一些分块算法来建立一些理解。
然后，我们将使用 Dask Array 并行分析大型数据集，使用熟悉的类似 NumPy 的 API。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相关文档&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/array.html"&gt;Array documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/9h_61hXCDuI"&gt;Array screencast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/array-api.html"&gt;Array API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://examples.dask.org/array.html"&gt;Array examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;matplotlib inline
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;%&lt;/span&gt;config InlineBackend&lt;span style="color:#f92672"&gt;.&lt;/span&gt;figure_format&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;retina&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="创建数据"&gt;创建数据&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;%run prep.py -d random
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="设置"&gt;设置&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask.distributed &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Client
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Client(n_workers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/dask/tutorial/array/pic-01.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="分块算法"&gt;分块算法&lt;/h2&gt;
&lt;p&gt;Blocked Algorithms&lt;/p&gt;
&lt;p&gt;&lt;em&gt;分块算法&lt;/em&gt; 通过将大型数据集分解为许多小块来在大型数据集上执行。&lt;/p&gt;
&lt;p&gt;例如，考虑取十亿个数字的总和。
我们可以将数组分成 1,000 个块，每个块的大小为 1,000,000，取每个块的总和，然后取中间总和的总和。&lt;/p&gt;
&lt;p&gt;我们通过执行许多较小的结果 (每个一百万个数字的一千个总和，然后是另一个一千个数字的总和) 来实现预期的结果 (一个十亿个数字的总和)。&lt;/p&gt;
&lt;p&gt;在以下示例中，我们使用 Python 和 NumPy 完全做到这一点：&lt;/p&gt;</description></item><item><title>Dask教程：Bag - 半结构化数据的并行列表</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-17-dask-tutorial-bag/</link><pubDate>Tue, 17 Aug 2021 22:49:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-17-dask-tutorial-bag/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dask-bag 擅长处理可以表示为任意输入序列的数据。
我们将其称为“杂乱”数据，因为它可能包含复杂的嵌套结构、缺失字段、数据类型的混合等。
函数式编程风格非常适合标准 Python 迭代，例如可以在 &lt;code&gt;itertools&lt;/code&gt; 模块中找到。&lt;/p&gt;
&lt;p&gt;当第一次消耗大量原始数据时，在数据处理管道的开始阶段经常会遇到凌乱的数据。
初始数据集可能是 JSON、CSV、XML 或任何其它不强制执行严格结构和数据类型的格式。
出于这个原因，最初的数据处理和处理通常是使用 Python &lt;code&gt;list&lt;/code&gt;s、&lt;code&gt;dict&lt;/code&gt;s 和 &lt;code&gt;set&lt;/code&gt;s 来完成的。&lt;/p&gt;
&lt;p&gt;这些核心数据结构针对通用存储和处理进行了优化。
使用迭代器/生成器表达式或诸如 &lt;code&gt;itertools&lt;/code&gt; 或 &lt;code&gt;toolz&lt;/code&gt; 之类的库添加流计算，让我们可以在小空间中处理大量数据。
如果我们将其与并行处理相结合，那么我们可以处理大量数据。&lt;/p&gt;
&lt;p&gt;Dask.bag 是一个高层 Dask 集合，用于自动化这种形式的常见工作负载。
简而言之&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;dask.bag = map, filter, toolz + parallel execution
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;相关文档&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/bag.html"&gt;Bag documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/-qIiJ1XtSv0"&gt;Bag screencast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/bag-api.html"&gt;Bag API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://examples.dask.org/bag.html"&gt;Bag examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="创建数据"&gt;创建数据&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;%run prep.py -d accounts
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="设置"&gt;设置&lt;/h2&gt;
&lt;p&gt;同样，我们将使用分布式调度器。
调度器将在后面深入解释。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask.distributed &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Client
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Client(n_workers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/python/dask/tutorial/bag/pic-01.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="创建"&gt;创建&lt;/h2&gt;
&lt;p&gt;可以从 Python 序列、文件、S3 上数据等创建 &lt;code&gt;Bag&lt;/code&gt;。
我们演示使用 &lt;code&gt;.take()&lt;/code&gt; 来显示数据元素。
执行 &lt;code&gt;.take(1)&lt;/code&gt; 会产生一个包含一个元素的元组。&lt;/p&gt;</description></item><item><title>论文阅读：监控超算中Scientific Python的使用情况</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-28-paper-thomas-2021-monitoring-python-usage/</link><pubDate>Sun, 15 Aug 2021 20:54:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-28-paper-thomas-2021-monitoring-python-usage/</guid><description>&lt;p&gt;Mointoring Scientific Python Usage on a Supercomputer&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thomas R, Stephey L, Greiner A, et al. Monitoring Scientific Python Usage on a Supercomputer[C]. Proceedings of the 20th Python in Science Conference (SciPy 2021). 2021. 101 - 109&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文发表于 SciPy 2021 会议，介绍如何监控高性能计算机上的 Python 库的使用情况，并对监控数据进行分析。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：以下正文部分翻译自论文，并根据笔者个人理解有所删改整合&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;本文包含两个主要内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;监控：使用 &lt;a href="https://github.com/NERSC/customs"&gt;Customs&lt;/a&gt; 包获取 Python 导入和其它作业数据&lt;/li&gt;
&lt;li&gt;分析：基于 Jupyter 分析框架的面板，使用 &lt;a href="https://github.com/nteract/papermill"&gt;Papermill&lt;/a&gt; 执行参数化笔记本，&lt;a href="https://github.com/rapidsai/cudf"&gt;Dask-cuDF&lt;/a&gt; 进行多 GPU 处理，&lt;a href="https://github.com/voila-dashboards/voila"&gt;Voila&lt;/a&gt; 将笔记本渲染成网页面板&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="介绍"&gt;介绍&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;工作负载分析&lt;/strong&gt; (Workload analysis) 是收集和整理数据以构建应用程序和用户如何真正与系统交互和利用系统的画像的过程。
可以用于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工程项目开发&lt;/li&gt;
&lt;li&gt;指导用户&lt;/li&gt;
&lt;li&gt;更新组件&lt;/li&gt;
&lt;li&gt;预测用户需求并相应地做好准备&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;全面、定量的工作负载分析是使 NERSC 成为高效的科学超级计算机中心的 &lt;strong&gt;关键&lt;/strong&gt; 工具。&lt;/p&gt;</description></item><item><title>读书笔记：我的二本学生</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-09-book-my-er-ben-student/</link><pubDate>Mon, 09 Aug 2021 21:05:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-09-book-my-er-ben-student/</guid><description>&lt;p&gt;本文记录 8 月第一周在读书小组发的读书笔记。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;《我的二本学生》 黄灯&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/book/my-er-ben-student/douban.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图片截图自豆瓣网站&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;在校外培训机构被严打、教育部长履新的背景下看这本书，更有现实意义。&lt;/p&gt;
&lt;p&gt;作者介绍自己当班主任的 06 级和 15 级，以及在这 10 年间通过导师制带的学生的经历和他们的感悟。
我正好是 06 级，而 15 级基本相当于最近几年入职的九零后同事。
本书通过记录这两代学生的经历，展现这十年间时代变化对年青一代的深刻影响。&lt;/p&gt;
&lt;p&gt;首先就是&lt;strong&gt;房价&lt;/strong&gt;，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;综观这个时代，可以发现，近十年内，顺着潮流，买房是个体获得巨额财富的捷径。
如果信奉劳动的价值，在房价相对平稳的实际，不愿加杠杆、不愿欠债，错过一步，可能就步步皆错，几年以后，就会形成触目惊心的对比。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一点在90后身上体现得更为明显，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1516045班没有一个外来的孩子，理直气壮地和我说起要待在大城市，更没有一个孩子相信凭自己的能力、工资，能够买得起一个安居之所，能够在流光溢彩的城市立下足。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同时作者认为&lt;strong&gt;家庭&lt;/strong&gt;对个人影响越来越重要，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;越是和学生深入交流，越能感知其背后的家庭，在他们身上烙下的印痕，学生成长的可能性，越来越受制于家庭的溢出效应。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;家庭做出的正确选择可以帮助孩子获得更好的教育，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;正是父母主动融入轰轰烈烈的城市化进程，孩子们才得以拥有机会获得教育资源，并迈进大学的校门。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;家庭的人脉资源可以为孩子的职场生涯带来各种便利，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大家都付出，但结果不一样，本来以为大家一起在爬树，但到最后，却发现人家没爬树，却用工具走捷径悄然摘走了苹果。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;家庭的力量可以给予孩子多次选择试错的余地，参考最近陈晓宇国籍事件，而很多年轻人&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;尽管一眼望穿了前景，却无法下定决心转身，恰恰在于自己没有任何承担风险的能力&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;作者也关注&lt;strong&gt;教育&lt;/strong&gt;的作用，正如 80 后学生说的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我们受过中国教育的一代回首过去，都埋怨它，记恨它，但又不得不承认，它给了我们这些寒门学子一条走向富裕、离开贫穷的道路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;尽管在被资本侵蚀越来越多的现在，教育仍然是一条走向成功的正确道路。
不难理解为什么越来越多的家长选择鸡娃教育，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在疯狂的追逐中，没有人可以容忍孩子的失败，现实强化的高校分层，学生也不容许自己失败。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;书中作者极端推崇体制内工作，虽然我也在事业单位，但作为经历九十年代末下岗大潮的青年人，我无法相信体制内工作就是铁饭碗，不赞同作者的倾向性。&lt;/p&gt;
&lt;p&gt;本以为通过读书上大学可以改变人生，读了这本书发现这可能只是我们这一代人享受到的时代红利。
一旦失去历史机遇，个人努力在社会大趋势面前会显得微不足道。&lt;/p&gt;
&lt;p&gt;尽管现实是个人越来越受制于家庭和时代，但总得给自己留些前进的希望不是，所以我还是相信通过个人的努力是可以改变生活的。
愿我们&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;继续为实现人民对美好生活的向往不懈努力&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://book.douban.com/subject/35050614/"&gt;豆瓣《我的二本学生》页面&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Dask教程：延迟执行</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-08-dask-tutorial-lazy/</link><pubDate>Sun, 08 Aug 2021 14:23:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-08-dask-tutorial-lazy/</guid><description>&lt;p&gt;在这里，我们将讨论 dask 背后的一些概念，以及代码的延迟执行。
如果您渴望继续学习本教程，则无需阅读这些材料，但它可能有助于理解 dask 背后的概念，这些内容如何与您可能已经在使用的技术相适应，以及如何理解可能出问题的事情。&lt;/p&gt;
&lt;h2 id="序幕"&gt;序幕&lt;/h2&gt;
&lt;p&gt;作为 Python 程序员，您可能已经执行了某些 &lt;em&gt;技巧&lt;/em&gt; 来启用大于内存数据集的计算、并行执行或延迟/后台执行。
也许用这种措辞，我们的意思不清楚，但一些例子应该会使事情更清楚。
Dask 的重点是让简单的事情变得简单，让复杂的事情成为可能！&lt;/p&gt;
&lt;p&gt;在&lt;a href="http://dask.pydata.org/en/latest/"&gt;详细的介绍&lt;/a&gt;之外，我们可以总结 Dask 的基础知识如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过将数据分成块并指定任务链来处理不适合内存的数据&lt;/li&gt;
&lt;li&gt;跨内核甚至集群节点并行执行任务&lt;/li&gt;
&lt;li&gt;将计算转移到数据而不是相反，以最大限度地减少通信开销&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有这些都可以让您充分利用计算资源，但以一种非常熟悉的方式进行编程：用于构建基本任务的 for 循环、Python 迭代器以及分别用于多维数据和表格数据的 NumPy (数组) 和 Pandas (数据框)。&lt;/p&gt;
&lt;p&gt;本笔记本的其余部分将带您了解这些编程范式中的第一个。
这比一些用户想要的要详细，他们可以跳到迭代器、数组和数据框部分；
但是会有一些数据处理任务不容易适应这些抽象，需要回退到这里的方法。&lt;/p&gt;
&lt;p&gt;我们在笔记本的末尾包含了一些示例，表明 Dask 的构建方式背后的想法实际上并不那么新颖，并且有经验的程序员之前会在其他情况下遇到过部分设计。
这些例子留给感兴趣的人。&lt;/p&gt;
&lt;h2 id="dask-是一个图执行引擎"&gt;Dask 是一个图执行引擎&lt;/h2&gt;
&lt;p&gt;Dask 允许您为要执行的计算构建一个处方 (recipe)。
这听起来可能很奇怪，但一个简单的示例将证明您可以在使用非常普通的 Python 函数和 for 循环进行编程时实现这一点。 我们在之前的笔记本已看到这一点。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask &lt;span style="color:#f92672"&gt;import&lt;/span&gt; delayed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@delayed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;inc&lt;/span&gt;(x):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@delayed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(x, y):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这里，我们使用了延迟注释来表明我们希望这些函数延迟运行 —— 保存输入集并仅在需要时执行。
&lt;code&gt;dask.delayed&lt;/code&gt; 也是一个可以做到这一点的函数，没有注释，保持原始函数不变，例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;delayed_inc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; delayed(inc)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面代码看起来像是普通代码&lt;/p&gt;</description></item><item><title>Dask教程：使用dask.delayed并行化代码</title><link>https://blog.perillaroc.wang/post/2021/08/2021-08-07-dask-tutorial-dask-delayed/</link><pubDate>Sun, 08 Aug 2021 12:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/08/2021-08-07-dask-tutorial-dask-delayed/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在本节中，我们使用 Dask 和 &lt;code&gt;dask.delayed&lt;/code&gt; 并行化简单的 for 循环样例代码。
通常，这是将函数转换为与 Dask 一起使用所需的唯一函数。&lt;/p&gt;
&lt;p&gt;这是使用 &lt;code&gt;dask&lt;/code&gt; 并行化现有代码库或构建复杂系统的一种简单方法。
这也将有助于我们对后面的部分进行理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相关文档&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/delayed.html"&gt;Delayed documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=SHqFmynRxVU"&gt;Delayed screencast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/delayed-api.html"&gt;Delayed API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://examples.dask.org/delayed.html"&gt;Delayed examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dask.org/en/latest/delayed-best-practices.html"&gt;Delayed best practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;正如我们将在分布式调度器笔记本中看到的，Dask 有多种并行执行代码的方法。
我们将通过创建 &lt;code&gt;dask.distributed.Client&lt;/code&gt; 来使用分布式调度器。
现在，这将为我们提供一些不错的诊断。
稍后我们将深入讨论调度器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; dask.distributed &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Client
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Client(n_workers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="基础"&gt;基础&lt;/h2&gt;
&lt;p&gt;首先让我们创建一些玩具函数，&lt;code&gt;inc&lt;/code&gt; 和 &lt;code&gt;add&lt;/code&gt;，它们会休眠一段时间来模拟工作。
然后我们将正常运行这些函数。&lt;/p&gt;
&lt;p&gt;在下一节中，我们将并行化此代码。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; time &lt;span style="color:#f92672"&gt;import&lt;/span&gt; sleep
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;inc&lt;/span&gt;(x):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sleep(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(x, y):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sleep(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们使用 &lt;code&gt;%%time&lt;/code&gt; magic 指令来计时这段普通代码的执行时间，这是 Jupyter Notebook 的一个特殊功能。&lt;/p&gt;</description></item><item><title>在Docker中安装NCL</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-27-install-ncl-in-docker/</link><pubDate>Tue, 27 Jul 2021 22:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-27-install-ncl-in-docker/</guid><description>&lt;p&gt;最近为 &lt;a href="https://github.com/nwpc-oper/sokort"&gt;sokort&lt;/a&gt; 项目封装 Docker 镜像，需要在镜像中安装 NCL 环境。
使用的基础镜像 (&lt;code&gt;jupyter/scipy-notebook&lt;/code&gt; 和 &lt;code&gt;continuumio/miniconda&lt;/code&gt;) 属于 debian buster 系列，安装的 NCL 版本较高，绘图脚本访问 GRAPES 系列模式 GRIB2 数据会出错，需要安装业务系统使用的 NCL 6.4.0 版本。
官网下载的预编译包依赖 libgfortran3 库，不能直接使用 &lt;code&gt;apt&lt;/code&gt; 安装，需要进行额外配置。&lt;/p&gt;
&lt;p&gt;下面介绍如何在 Ubuntu 20.04 和 Debian buster 的 Docker 镜像中安装 NCL 6.4.0 版本。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;从官方渠道下载 NCL 预编译包。本文下载的软件包是&lt;/p&gt;
&lt;p&gt;ncl_ncarg-6.4.0-Debian8.6_64bit_nodap_gnu492.tar.gz&lt;/p&gt;
&lt;h2 id="ubuntu-2004-jupyterscipy-notebook"&gt;Ubuntu 20.04 (jupyter/scipy-notebook)&lt;/h2&gt;
&lt;p&gt;准备 apt 源文件 &lt;code&gt;sources.list&lt;/code&gt;，本文使用 CMA 镜像站加速。
注意添加 Ubuntu 18.04 (bionic) 源。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;deb http://mirrors.cma.cn/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.cma.cn/ubuntu/ focal-updates main restricted universe multiversemultiverse
deb http://mirrors.cma.cn/ubuntu/ focal-backports main restricted universe multiverse

deb http://mirrors.cma.cn/ubuntu/ bionic main universe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 &lt;code&gt;Dockerfile&lt;/code&gt; 文件中覆盖 &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; 并安装 &lt;code&gt;g++-6&lt;/code&gt; 和 &lt;code&gt;libgfortran3&lt;/code&gt;&lt;/p&gt;</description></item><item><title>读书笔记：女性的时刻 + 另一半的天空</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-27-book-women/</link><pubDate>Tue, 27 Jul 2021 21:21:15 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-27-book-women/</guid><description>&lt;p&gt;本文记录 6 月第一周在读书小组内发的读书笔记。&lt;/p&gt;
&lt;p&gt;在读书群里同志的感召下，读了两本关注女性发展的书，其中都提到女性面临的各种困境，包括教育、家庭、生育、工作及性工作者，并介绍世界优秀人士在男女平等上的做出努力和贡献，让我对慈善行业有了更详细更全面的了解。&lt;/p&gt;
&lt;p&gt;《女性的时刻》中介绍了作者生活家庭经历，在作者离婚热点新闻的背景下读这本书，就有更深入的体会。
不过我并不赞同书中的一些观点，尤其是对性工作者发放艾滋病预防药，而不是参考新中国已成功实现的改造工作，怀疑是不是打着慈善的名义帮医药公司在第三世界国家进行人体实验。&lt;/p&gt;
&lt;p&gt;《另一半的天空》提到的扶贫小额信贷在国内脱贫攻坚战中同样发挥了重要的作用。
书中对于性工作者、自主计划生育等方面的观念冲突有更多角度的描述。
我也比较困惑，面对价值观的冲突，到底什么才是正义，是否有普世价值？&lt;/p&gt;
&lt;p&gt;我们党早在一百年前的中共二大《关于妇女运动的决议》中就指出&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;中国共产党认为妇女解放是要伴着劳动解放进行的，只有无产阶级获得了政权妇女们才能得到真正解放。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以对于慈善能否真正改变贫穷落后的现状，我抱有怀疑的态度。&lt;/p&gt;
&lt;p&gt;《另一半的天空》开篇引用一句中国谚语&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;女人能顶半边天&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我觉得任何宣传口号都没有这句话响亮，愿我们生活在一个人人平等的世界中。&lt;/p&gt;
&lt;p&gt;下一阶段转向阅读近现代中国历史，了解中国是如何在一个世纪内从贫穷落后走向繁荣富强的。&lt;/p&gt;</description></item><item><title>论文阅读：模式运行工具 ESM-Tools</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-24-paper-barbi-2021-esm-tools/</link><pubDate>Sun, 25 Jul 2021 21:50:05 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-24-paper-barbi-2021-esm-tools/</guid><description>&lt;p&gt;ESM-Tools version 5.0: a modular infrastructure for stand-alone and coupled Earth system modelling (ESM)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Barbi D, Wieters N, Gierz P, et al. ESM-Tools version 5.0: a modular infrastructure for stand-alone and coupled Earth system modelling (ESM)[J]. Geoscientific Model Development, 2021, 14(6): 4051-4067. &lt;a href="https://doi.org/10.5194/gmd-14-4051-2021"&gt;https://doi.org/10.5194/gmd-14-4051-2021&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;论文介绍一款用于地球系统模式工作流和基础设施管理的工具 ESM-Tools，用于在多种不同的 HPC 环境中下载、配置、编译、运行和监控地球系统模式的分量模式和耦合模式。&lt;/p&gt;
&lt;p&gt;ESM-Tools 的目标是帮助科研用户快速运行模式，用户仅需提供少量脚本即可运行完整的模拟实验。
该工具利用模式现有的配置接口，不对模式本身进行修改，通过 YAML 配置文件提供对不同模式的支持，核心代码与具体的模式无关。
对于我们正考虑构建模式系统统一运行流程来说，ESM-Tools 是非常合适的参考工具。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下正文章节摘自论文，并根据笔者个人理解所有删改和整合。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="介绍"&gt;介绍&lt;/h3&gt;
&lt;p&gt;地球系统模式 (ESM) 应用的完整流程包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取并编译所有源代码&lt;/li&gt;
&lt;li&gt;管理输入数据和配置文件&lt;/li&gt;
&lt;li&gt;提交可执行程序到一个多处理器系统&lt;/li&gt;
&lt;li&gt;监控并记录运行过程&lt;/li&gt;
&lt;li&gt;管理 / 后处理模式输出&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ESM-Tools 通过单独的脚本提供典型任务的标准解决方案，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;日历计算&lt;/li&gt;
&lt;li&gt;数据后处理&lt;/li&gt;
&lt;li&gt;监控&lt;/li&gt;
&lt;li&gt;完整性检查&lt;/li&gt;
&lt;li&gt;排序和归档输出&lt;/li&gt;
&lt;li&gt;离线耦合&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ESM-Tools 提供标准化框架，用于在不同的 HPC 上为 ESM 提供：&lt;/p&gt;</description></item><item><title>论文阅读：探索数据分析工具 DataPrep.EDA</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-12-paper-peng-2021-dataprep-eda/</link><pubDate>Sun, 18 Jul 2021 18:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-12-paper-peng-2021-dataprep-eda/</guid><description>&lt;p&gt;DataPrep.EDA: Task-Centric Exploratory Data Analysis for Statistical Modeling in Python&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Peng J, Wu W, Lockhart B, et al.
DataPrep. EDA: Task-Centric Exploratory Data Analysis for Statistical Modeling in Python[C]
//Proceedings of the 2021 International Conference on Management of Data.
2021: 2271-2280.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍用于探索性数据分析 (EDA) 的 Python 库 DataPrep.EDA。
我很少进行探索性数据分析，阅读这篇文章主要用来借鉴数据处理/分析库的设计思想和实现方式。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="设计理念"&gt;设计理念&lt;/h3&gt;
&lt;p&gt;对于统计模型，探索性数据分析通常分解为多个任务，本文关注如下三种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理解单个变量 (univariate analysis)&lt;/li&gt;
&lt;li&gt;理解两个随机变量之间的关系 (bivariate analysis)&lt;/li&gt;
&lt;li&gt;了解缺失值的影响 (missing value analysis)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DataPrep.EDA 使用以任务为中心的方法，实现三个设计目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方便使用：每个 EDA 任务对应一个函数调用，类似调用单个函数就可以绘制一张图片 (&lt;code&gt;xarray.DataArray.plot&lt;/code&gt;)。
根据数据内容自动进行分析和绘图。&lt;/li&gt;
&lt;li&gt;交互速度：避免无关计算，使用Dask加速，可以用于交互分析&lt;/li&gt;
&lt;li&gt;方便定制：提供通用参数和并在结果中显示指南&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三个库的对比&lt;/p&gt;</description></item><item><title>Dask教程：简介</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-10-dask-tutorial-overview/</link><pubDate>Sat, 10 Jul 2021 21:42:20 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-10-dask-tutorial-overview/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/dask/dask-tutorial"&gt;dask-tutorial&lt;/a&gt; 项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;欢迎来到 Dask 教程。&lt;/p&gt;
&lt;p&gt;Dask 是一个并行计算库，可扩展现有的 Python 生态系统。
本教程将更一般地介绍 Dask 和并行数据分析。&lt;/p&gt;
&lt;p&gt;Dask 可以缩小到您的笔记本电脑，也可以扩展到集群中。
在这里，我们将使用您在笔记本电脑上设置的环境，在本地并行分析中等规模的数据集。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;Dask 在大于内存 (larger-than-memory) 的数据集上提供多核和分布式并行执行。&lt;/p&gt;
&lt;p&gt;我们可以从高层和底层来考虑 Dask&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;高层集合&lt;/strong&gt;：Dask 提供了模拟 NumPy、lists 和 Pandas 的高层 Array、Bag 和 DataFrame 集合，但可以在不适合内存的数据集上并行操作。
对于大型数据集，Dask 的高层集合是 NumPy 和 Pandas 的替代品。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;底层调度程序&lt;/strong&gt;：Dask 提供了并行执行任务图的动态任务调度程序。
这些执行引擎支持上面提到的高级集合，但也支持自定义的、用户定义的工作负载。
这些调度程序是低延迟的 (大约 1 毫秒)，并且努力在很小的内存占用中运行计算。
Dask 的调度程序是在复杂情况下直接使用 &lt;code&gt;threading&lt;/code&gt; 或 &lt;code&gt;multiprocessing&lt;/code&gt; 库或其他任务调度系统 (如 &lt;code&gt;Luigi&lt;/code&gt; 或 &lt;code&gt;IPython parallel&lt;/code&gt;) 的替代方案。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同的用户在不同的级别上操作，但了解两者很有用。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stories.dask.org/en/latest/"&gt;Dask 用例&lt;/a&gt;提供了许多 Dask 应该很适合的示例工作流。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;你应该克隆这个存储库：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone http://github.com/dask/dask-tutorial
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;binder&lt;/code&gt; 子目录中包含的文件 &lt;code&gt;environment.yml&lt;/code&gt; 包含运行本教程所需的所有包的列表。
要使用 &lt;code&gt;conda&lt;/code&gt; 安装它们，您可以执行以下操作:&lt;/p&gt;</description></item><item><title>2021年第二季度工作总结</title><link>https://blog.perillaroc.wang/post/2021/07/2021-07-06-2021-q2-summary/</link><pubDate>Sat, 10 Jul 2021 21:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/07/2021-07-06-2021-q2-summary/</guid><description>&lt;p&gt;第二季度深切体会到坚持“充电”需要强大的自控力。
无论是工作还是家庭，总能找到理由来说服自己寻找各种各样的方式来消磨时间，逃避充满艰辛的充电奋斗之路。
第二季度尤其是整个 6 月，我几乎没有利用任何可自由支配时间进行有效学习。
也许是因为空闲时间变得比之前更为零散，但归根到底还是没有坚持的魄力，让我不禁怀疑自己是不是已进入了 35 岁魔咒时期。&lt;/p&gt;
&lt;h2 id="计划完成情况"&gt;计划完成情况&lt;/h2&gt;
&lt;p&gt;上一季度总结中计划今年第二季度完成以下工作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✔️ 现代化专项验收&lt;/li&gt;
&lt;li&gt;✔️ TYM 升级&lt;/li&gt;
&lt;li&gt;nwpc-data
&lt;ul&gt;
&lt;li&gt;❌ 格式支持&lt;/li&gt;
&lt;li&gt;✔️ 数据处理 API&lt;/li&gt;
&lt;li&gt;❌ 数据源&lt;/li&gt;
&lt;li&gt;✔️ ML 算法&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;❌ ESMValTool + 工作流组件&lt;/li&gt;
&lt;li&gt;sokort
&lt;ul&gt;
&lt;li&gt;✔️ 完善功能&lt;/li&gt;
&lt;li&gt;❌ 加工流水线&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;❌ 升级 ecFlow&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作"&gt;工作&lt;/h2&gt;
&lt;h3 id="业务系统升级更新"&gt;业务系统升级更新&lt;/h3&gt;
&lt;p&gt;第二季度的重点任务是完成 GRAPES TYM 3.1 版本升级。对于流程构建来说，新版本仅增加全球台风报文获取和云分析模块，其他变化隐藏在系统脚本之中。
整合脚本有利于快速完成业务系统流程构建任务。
6月份的特殊保障服务要求 MESO 从 36 小时延长到 72 小时，鉴于之前已优化过后处理系统流程，仅需要修改少量代码就可以实现对特定时次预报时长的修改。&lt;/p&gt;
&lt;p&gt;原计划在第二季度完成的 GRAPES MESO 版本升级推迟到第三季度，TYM 代替 MESO 10KM 也将在第三季度完成。&lt;/p&gt;
&lt;p&gt;随着系统逐渐增多，流程整合的需求变得越来越强。
如果时间充裕，可以考虑从后处理系统入手，研究如何能将业务系统的流程构建进行整合，共享相同的组件，简化 ecFlow 系统构建代码，为进一步整合业务系统构建进行前期探索。&lt;/p&gt;
&lt;h3 id="数据工具"&gt;数据工具&lt;/h3&gt;
&lt;p&gt;数据工具是第二季度的主要工作。为用户提供方便易用的数据处理工具是我最近两年的核心目标。&lt;/p&gt;
&lt;h4 id="数据处理"&gt;数据处理&lt;/h4&gt;
&lt;p&gt;更新 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库：&lt;/p&gt;</description></item><item><title>使用era5cli下载ERA5数据</title><link>https://blog.perillaroc.wang/post/2021/06/2021-06-22-download-era5-using-era5cli/</link><pubDate>Tue, 22 Jun 2021 22:45:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/06/2021-06-22-download-era5-using-era5cli/</guid><description>&lt;p&gt;本文介绍如何使用 &lt;a href="https://github.com/eWaterCycle/era5cli"&gt;era5cli&lt;/a&gt; 批量下载 ERA5 数据。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文部分内容来自 &lt;a href="https://era5cli.readthedocs.io/en/stable/"&gt;era5cli 官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;使用 pip 安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install era5cli
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者从 GITHUB 网站下载源码在线安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install -U git+https://github.com/eWaterCycle/era5cli.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装后会提供命令行程序 &lt;code&gt;era5cli&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;h3 id="注册账户"&gt;注册账户&lt;/h3&gt;
&lt;p&gt;下载 ERA5 数据需要注册 Copernicus CDS 账户：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://cds.climate.copernicus.eu/user/register?destination=%2F%23!%2Fhome"&gt;https://cds.climate.copernicus.eu/user/register?destination=%2F%23!%2Fhome&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;注册并登陆后，在个人资料界面可以找到 UID 和 API key。&lt;/p&gt;
&lt;h3 id="创建配置文件"&gt;创建配置文件&lt;/h3&gt;
&lt;p&gt;era5cli 默认使用用户目录下的配置文件。&lt;/p&gt;
&lt;p&gt;在用户目录 (&lt;code&gt;$HOME&lt;/code&gt;) 创建配置文件 &lt;code&gt;.cdsapirc&lt;/code&gt;，包含两行内容&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;url: https://cds.climate.copernicus.eu/api/v2
key: UID:KEY
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中 &lt;code&gt;UID&lt;/code&gt; 和 &lt;code&gt;KEY&lt;/code&gt; 是上一步在个人资料界面中找到的值。&lt;/p&gt;
&lt;h2 id="查看信息"&gt;查看信息&lt;/h2&gt;
&lt;p&gt;下载数据前，我们需要知道数据集的基本信息，以便确定筛选条件。
era5cli 提供下面的命令用于查看可用的变量和层次&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;era5cli info &lt;span style="color:#f92672"&gt;[&lt;/span&gt;-h&lt;span style="color:#f92672"&gt;]&lt;/span&gt; name
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;name&lt;/code&gt; 可以是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;levels&lt;/code&gt;：显示所有气压层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2Dvars&lt;/code&gt;：显示所有单层或二维变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3Dvars&lt;/code&gt;：显示所有三维变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;land&lt;/code&gt;：显示所有 &lt;code&gt;ERA5-land&lt;/code&gt; 中的变量&lt;/li&gt;
&lt;li&gt;变量名 (例如 &lt;code&gt;total_precipitation&lt;/code&gt;) 或气压层 (例如 &lt;code&gt;825&lt;/code&gt;)：显示变量或层次是否可用，以及在哪个列表中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;</description></item><item><title>R语言实战：使用ggplot2进行高级绘图</title><link>https://blog.perillaroc.wang/post/2021/06/2021-06-06-r-in-action-ggplot2/</link><pubDate>Sun, 06 Jun 2021 16:02:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/06/2021-06-06-r-in-action-ggplot2/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍ggplot2包&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ggplot2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(car)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(gridExtra)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="r-中的四种图形系统"&gt;R 中的四种图形系统&lt;/h2&gt;
&lt;p&gt;基础图形系统&lt;/p&gt;
&lt;p&gt;grid 图形系统&lt;/p&gt;
&lt;p&gt;lattice 包&lt;/p&gt;
&lt;p&gt;ggplot2 包&lt;/p&gt;
&lt;h2 id="ggplot2-包介绍"&gt;ggplot2 包介绍&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ggplot&lt;/span&gt;(data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mtcars, &lt;span style="color:#a6e22e"&gt;aes&lt;/span&gt;(x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;wt, y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mpg)) &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;geom_point&lt;/span&gt;() &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labs&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Automobile Data&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Weight&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Miles Per Gallon&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/r/ria/chap19/mtcar-1.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;添加线性拟合&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ggplot&lt;/span&gt;(data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mtcars, &lt;span style="color:#a6e22e"&gt;aes&lt;/span&gt;(x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;wt, y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mpg)) &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;geom_point&lt;/span&gt;(pch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;, color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;blue&amp;#34;&lt;/span&gt;, size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;geom_smooth&lt;/span&gt;(method&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;lm&amp;#34;&lt;/span&gt;, color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;red&amp;#34;&lt;/span&gt;, linetype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labs&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Automobile Data&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Weight&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Miles Per Gallon&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/r/ria/chap19/mtcar-2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;将变量转为因子&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;am &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;factor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;am, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; levels&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; labels&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Automatic&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Manual&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;vs &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;factor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;vs,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; levels&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; labels&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;V-Engine&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Straight Engline&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;cyl &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;factor&lt;/span&gt;(mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;cyl)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分组和面&lt;/p&gt;</description></item><item><title>读书笔记：气候经济与人类未来</title><link>https://blog.perillaroc.wang/post/2021/06/2021-06-04-book-how-to-avoid-a-climate-disaster/</link><pubDate>Sun, 06 Jun 2021 15:44:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/06/2021-06-04-book-how-to-avoid-a-climate-disaster/</guid><description>&lt;blockquote&gt;
&lt;p&gt;气候经济与人类未来：比尔·盖茨给世界的解决方案&lt;/p&gt;
&lt;p&gt;How to Avoid a Climate Disaster: The Solutions We Have and the Breakthroughs We Need&lt;/p&gt;
&lt;p&gt;by Bill Gates&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;碳中和背景下一本非常好的入门书籍，从能源、制造业、农业、交通运输、取暖制冷等五个方面介绍人类活动对温室气体排放的影响及可行的解决方案，同时还提出作者自己的解决方案，包括个人、企业、政府应该如何协作以应对气候变化问题。&lt;/p&gt;
&lt;h2 id="温室气体来源"&gt;温室气体来源&lt;/h2&gt;
&lt;p&gt;我从书中看到，减少人类活动排放温室气体的核心是能源问题，也就是我们能不能获取到“零碳”电力，既能满足未来发展的需求又成本低廉。
交通运输业、制冷和取暖实质也是能源的问题，使用电力代替燃油、燃煤。
我认为，从能源安全角度来说，国内未来一定是新能源汽车的天下。&lt;/p&gt;
&lt;p&gt;作者在前言中就提到自己投资了清洁能源公司，包括一家核电站公司，并抱怨为什么不用下一代核电站技术，中国和俄罗斯为什么开发自己的核电站技术。
我觉得在这一点上还真不能使用私人公司开发的未经验证的所谓新一代技术，像能源这种具有战略意义的资源，绝对不能依赖其他国家提供。&lt;/p&gt;
&lt;p&gt;对于制造业，作者极力推崇碳捕获装置和直接空气捕获技术，同时对于零碳产品的高昂成本，建议政府用外力强迫消费者使用。&lt;/p&gt;
&lt;p&gt;在农业方面，我从书中学到了一个意想不到的新知识：牛会影响气候变化。
作者建议减少肉类使用，而使用人造肉或植物肉代替，并乐观地认为成本最终会低于真正的动物肉制品价格。
同时作者极力淡化植树造林的功效，忽略陆地碳汇能力，而推崇“直接空气捕获”技术。&lt;/p&gt;
&lt;h2 id="经济问题"&gt;经济问题&lt;/h2&gt;
&lt;p&gt;中译本的题目中“气候经济”是对这本书内容的完美诠释。
气候变化实际上是一个经济问题，而不是环境问题。&lt;/p&gt;
&lt;p&gt;“经济”二字在书中却有非常全面的体现，作者给出的大部分解决方案非常巧合地都是盖茨基金会投资的领域。
比如直接空气捕获，新一代核裂变技术，人造肉，疫苗，培育种子等等。
表面上谈的是人类的未来，实际上也都是所谓的生意。&lt;/p&gt;
&lt;p&gt;作者甚至还提到自己投资的地球工程领域，即“对海洋或大气层采取干预措施，对其进行临时改变，从而达到降低全球温度的目的”，认为只有这项技术能实现降低温度且避免经济严重受损。
在我看来，这种高阶版的人工影响天气即便可行也因为政治原因而没有实现的可能。
2017 年有部电影《全球风暴》就讲了如果这种技术成为现实，那后果将不可预料。&lt;/p&gt;
&lt;p&gt;作者为政府在气候变化相关技术研究中应该扮演的角色进行了详尽的阐述，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发前期技术，然后为私人企业让路&lt;/li&gt;
&lt;li&gt;通过提高碳排放产品价格来创建公平竞争环境&lt;/li&gt;
&lt;li&gt;破除非市场壁垒&lt;/li&gt;
&lt;li&gt;紧跟时代步伐&lt;/li&gt;
&lt;li&gt;规划“公正转型”，认真对待受到冲击的产业工人&lt;/li&gt;
&lt;li&gt;迎难而上，解决最根本的能源问题&lt;/li&gt;
&lt;li&gt;技术、政策和市场三管齐下，建议政府为作者投资的先进核技术建立试点项目&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强调政府的作用，类似再分配，由消费者为新技术的额外成本买单，却认为资本在利益驱动下可以有所作为，过度看重企业的作用，让我再次感到以公有制为主体社会主义市场经济的制度优势。&lt;/p&gt;
&lt;h2 id="对贫困群体的关注"&gt;对贫困群体的关注&lt;/h2&gt;
&lt;p&gt;提到气候问题，就不能不提到发展的问题。
作者在开篇就提到盖茨基金会的核心理念：“每个人都应该有机会过上健康而富有成效的生活”，一句非常有力量的宣传口号。&lt;/p&gt;
&lt;p&gt;作者认为 “试图阻断处于经济阶梯底层的人的上升通道是不道德的，也是不切实际的”，指出“在气候变化问题上，贫困者是最大的输家”，“没做任何导致气候变化的事情，其所承受的气候变化带来的冲击却最大”。
作者认为“这个世界需要更多的能源，才能使贫困群体走上富裕道路，但我们不能以增加温室气体的排放为代价”。&lt;/p&gt;
&lt;p&gt;不过，我倒是觉得对于贫困国家来说，想要在绿色发展可能是一条充满艰辛的曲折之路。
实际上即便不考虑气候问题，脱贫都不是一件容易的事情。
作者对家庭摆脱贫困并成功加入全球中产阶级行列抱有过于乐观的态度。
参考辛亥革命后，有人要搞经济建设提高民生，认为继续搞革命会导致共和破裂，而以袁世凯为代表的北洋军阀给这些人上了重要的一课，告诉他们不扫清旧势力是无法开展建设的。&lt;/p&gt;
&lt;h2 id="先行者优势"&gt;先行者优势&lt;/h2&gt;
&lt;p&gt;本书中各个案例让我意识到先行者优势的重要性。
无论科学最终证明人为活动是否会导致全球变暖，气候问题已然成为一张政治王牌。
对于尚需要发展时间的国家来说，顶在头上除民主和人权两座山外，又增加了一座名为气候变化的大山。&lt;/p&gt;
&lt;p&gt;各个国家的发展过程可能不尽相同，但气候变化成为热点问题后，对于后发国家来说，前人道路已不可行，只能依照先发国家制定的各项规则，在条条框框之内探索发展之路。
这不是一件容易的事情，即便拥有辉煌历史的中国，也用了一百年的时间。而妄图依靠外国援助和私人慈善，可能永远也走不上民族富强的道路。
参考北洋军阀时期帝国主义列强扶植中国代理人，以某些特权作为交换而提供金钱和武器支持。&lt;/p&gt;
&lt;p&gt;如果核聚变能投入商业化，也许碳中和的目标会更容易实现，而我们也许会迎来继民主、人权、气候之后的下一个全球政治热门话题。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;书中给出了气候科学在气候变化中的定位，很有参考意义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;气候科学告诉我们的是，我们为什么要应对这个问题，而不是我们该如何应对这个问题。&lt;/p&gt;</description></item><item><title>GRIB笔记：为GRIB 2文件创建要素场描述表格</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-17-grib-notebook-create-fields-table/</link><pubDate>Thu, 27 May 2021 20:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-17-grib-notebook-create-fields-table/</guid><description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;本文介绍如何从 GRIB 2 文件读取元信息，创建文件内容描述表格，表格中每行代表文件中的一个 GRIB 2 要素场。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;本文面向 GRAPES 系列模式数据创建要素场信息描述表格。&lt;/p&gt;
&lt;p&gt;GRAPES 系列模式的相关发文中已提供详细的预报产品清单，不过清单中给出的序号并不是要素场在 GRIB 2 文件中的序号。
虽然我们从 GRIB 2 文件中载入某个要素场也不应该依赖要素场在文件中的序号，但按要素场序号排序的清单有助于对自定义编码变量的理解。&lt;/p&gt;
&lt;h2 id="方法"&gt;方法&lt;/h2&gt;
&lt;p&gt;使用 ecCodes 解码 GRIB 2 格式数据。
ecCodes 定义一系列 GRIB Key 用于从 GRIB 2 消息中读取元信息，非常方便易用。&lt;/p&gt;
&lt;p&gt;GRAPES 系列模式 GRIB 2 产品单个文件中仅包含单个时次单个时效单个预报成员的要素场，所以清单中仅需要包含与要素场本身相关的信息。&lt;/p&gt;
&lt;p&gt;本文从读取如下三个方面的元数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要素：要素场表示什么物理量，例如温度、湿度、风等&lt;/li&gt;
&lt;li&gt;垂直层次：要素场在垂直方向上的位置，例如地面、850hPa 等等&lt;/li&gt;
&lt;li&gt;时间信息：要素场在时间上的类型和范围，比如要素场可能表示瞬时值 (10m 风)，或区间值统计值 (10m 最大风速)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体读取的 GRIB Key 列表如下：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;key&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;序号&lt;/td&gt;
					&lt;td&gt;count&lt;/td&gt;
					&lt;td&gt;序号&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;要素&lt;/td&gt;
					&lt;td&gt;shortName&lt;/td&gt;
					&lt;td&gt;简称 (可能为 unknown)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;discipline&lt;/td&gt;
					&lt;td&gt;学科 (均为 0)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;parameterCategory&lt;/td&gt;
					&lt;td&gt;分类&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;parameterNumber&lt;/td&gt;
					&lt;td&gt;变量代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;垂直层次&lt;/td&gt;
					&lt;td&gt;typeOfLevel&lt;/td&gt;
					&lt;td&gt;层次类型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;level&lt;/td&gt;
					&lt;td&gt;层次值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;typeOfFirstFixedSurface&lt;/td&gt;
					&lt;td&gt;第一层类型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;scaleFactorOfFirstFixedSurface&lt;/td&gt;
					&lt;td&gt;第一层因子&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;scaledValueOfFirstFixedSurface&lt;/td&gt;
					&lt;td&gt;第一层值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;typeOfSecondFixedSurface&lt;/td&gt;
					&lt;td&gt;第二层类型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;scaleFactorOfSecondFixedSurface&lt;/td&gt;
					&lt;td&gt;第二层因子&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;scaledValueOfSecondFixedSurface&lt;/td&gt;
					&lt;td&gt;第二层值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;时间信息&lt;/td&gt;
					&lt;td&gt;stepRange&lt;/td&gt;
					&lt;td&gt;时效范围&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;stepType&lt;/td&gt;
					&lt;td&gt;时效类型&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;ecCodes 中 GRIB Key 的值可以用多种类型表示&lt;/p&gt;</description></item><item><title>论文阅读：科学攻陷云平台</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-17-paper-gentemann-2021-science-storms-the-cloud/</link><pubDate>Wed, 26 May 2021 22:09:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-17-paper-gentemann-2021-science-storms-the-cloud/</guid><description>&lt;p&gt;&lt;strong&gt;Science storms the cloud&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gentemann, C. L., Holdgraf, C., Abernathey, R., Crichton, D., Colliander, J., Kearns, E. J., et al. (2021). Science storms the cloud. AGU Advances, 2, e2020AV000354. &lt;a href="https://doi.org/10.1029/2020AV000354"&gt;https://doi.org/10.1029/2020AV000354&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;发表于 AGU Advances 的一篇文章，介绍科学尤其是地球科学正在向云计算平台迁移的趋势。
虽然我不认为云平台就一定能降低科学研究的入门门槛，但我还是非常赞同文中对开放科学的支持态度。
标题是双关语，起得很有意思。&lt;/p&gt;
&lt;p&gt;以下“正文”章节翻译自论文，底稿来自谷歌翻译，并按照笔者的个人理解有所修改。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="摘要"&gt;摘要&lt;/h3&gt;
&lt;p&gt;科学的核心工具 (数据，软件和计算机) 正在经历历史性的快速发展，改变了科学家提出的问题以及如何找到答案。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数据&lt;/strong&gt;：地球科学数据正在转换为针对云存储进行优化的新格式，从而可以快速分析 PB 级数据集。
数据集正在从存档中心转移到与大型服务器场相邻的庞大云数据存储中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;平台&lt;/strong&gt;：可通过浏览器窗口访问的基于开源云架构的数据科学平台，让科学家在连接到 Internet 的任何地方都可以从事高级、协作、跨学科的科学研究。
用于机器学习和人工智能的专用软件和硬件已集成到数据科学平台中，从而使普通科学家更容易使用它们。&lt;/p&gt;
&lt;p&gt;云中越来越多的数据和计算能力正在开启数据驱动发现的新方法。
第一次，科学家无需专业云计算知识就可以将分析应用于云中的数据变得真正可行。
这种范式的转变有可能降低准入门槛，扩大科学社区，增加合作机会，同时促进科学创新，提高透明度和可重复性。&lt;/p&gt;
&lt;p&gt;然而，我们所有人都目睹了有希望的新工具从一开始似乎无害且有益，变得具有破坏性或带来限制。
随着这种新的科学方法不断发展，我们需要考虑什么？&lt;/p&gt;
&lt;h3 id="通俗语言摘要"&gt;通俗语言摘要&lt;/h3&gt;
&lt;p&gt;长期以来，科学家一直在下载数据并在自己的计算机上进行分析。
由于其他人无法访问相同的数据，软件和计算资源，因此协作变得非常困难。
这种方式还为具有高速互联网和大量计算机的大型机构科学家提供了优势。&lt;/p&gt;
&lt;p&gt;现在，数据正在存储在云中，科学家正在共享他们的软件，任何人都可以通过 Web 浏览器访问云中的计算机。
因为每个人都可以访问相同的数据，软件和计算机，所以这使得协作更容易。
而且，更多的人可以使用功能强大的计算机从事科学工作。
这是科学的另一种方式，同样存在潜在的弊端。
我们需要小心，这种新的科学方法实际上可以促进科学发展，并包括更多的人，以便我们更快地获得更好的答案。&lt;/p&gt;
&lt;h3 id="介绍"&gt;介绍&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;科学的新方向是由新工具发起的，而不是由新概念发起的。
概念驱动的革命的效果是用新的方式解释旧事物。
工具驱动革命的结果是发现必须解释的新事物。
(Freeman Dyson)&lt;/p&gt;</description></item><item><title>读书笔记：我们为什么要睡觉？</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-24-book-why-we-sleep/</link><pubDate>Mon, 24 May 2021 21:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-24-book-why-we-sleep/</guid><description>&lt;blockquote&gt;
&lt;p&gt;我们为什么要睡觉？&lt;/p&gt;
&lt;p&gt;Why We Sleep: Unlocking the Power of Sleep and Dreams&lt;/p&gt;
&lt;p&gt;by Matthew Walker&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文记录 5 月在读书小组内发的 2 段读书笔记。&lt;/p&gt;
&lt;h2 id="第一部--第二部"&gt;第一部 + 第二部&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“科学家发现延长人类寿命的革命性新疗法！这种疗法能增强记忆、激发创意，… 让你保持苗条 … 保护你不得癌症、不失智 … 降低心脏病发和中风风险 … 让你更快乐，减少忧郁，不易焦虑。”&lt;/p&gt;
&lt;p&gt;—— 实际上这不是一种奇迹般的新药，而全是充足睡眠的明确好处。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对于经常熬夜的人来说，这是一本非常值得看的书。
它会告诉你人们为什么需要在合适的时间进行足够的睡眠。
同时，这也是一本看了可能会后悔的书，因为读后再熬夜就总会有一种罪恶感，觉得自己正在自我破坏，而且没有回头路。&lt;/p&gt;
&lt;p&gt;按时睡觉符合生理规律。
我们的睡眠受两个因素影响：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一是称为“近日节律”的内在24小时时钟讯号，让我们在夜间疲倦而在白天清醒；&lt;/li&gt;
&lt;li&gt;一是只要清醒就会在脑中积累的一种化学物质，会制造出“睡眠压力”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两个因素相互独立，共同决定我们的睡眠压力。
当熬夜后第二天白天可能感觉到的暂时清醒，并不意味着我们用意志克服了睡意，这只是近日节律发挥了作用。&lt;/p&gt;
&lt;p&gt;我一直觉得只要补够睡眠小时数，晚睡一两个小时熬下夜没什么。
可是这本书却明确地告诉我这样做是没有意义的。&lt;/p&gt;
&lt;p&gt;睡眠有两种形式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非快速眼动睡眠是进行“反思”，对新事实、新技能的原料存储和巩固；&lt;/li&gt;
&lt;li&gt;快速眼动睡眠则是“整合”，为新原料建立彼此之间的连接，并与过去经验结合，产生崭新的洞见和解决问题的能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整个睡眠周期是两种睡眠形式相互拉锯的循环。
每次循环九十分钟，一共五个周期，每个周期睡眠形式比例不同，有特殊的作用，这也是要保证连续八小时睡眠的缘由。
早起会损失大量快速眼动睡眠，而晚睡则会损失大量的深度非快速眼动睡眠。
对于先前损失的睡眠，人类永远无法事后“补回来”。
同时，书中还提到人类天生适合“&lt;strong&gt;两段式睡眠&lt;/strong&gt;”，即一段连续长时间的夜间睡眠，加上一段较短的午睡。&lt;/p&gt;
&lt;p&gt;睡眠能提升大脑的学习力。
睡眠可以恢复学习能力，午睡能帮助记忆。学习之后的睡眠可以帮助巩固记忆。
睡眠可以帮助我们恢复记忆，帮助我们遗忘痛苦的回忆，提升运动能力，还会提升创造力。
而睡眠缺失会对我们的大脑带来严重的影响，影响专注力，影响我们对缺觉的判断力，让我们丧失理性思维，在情绪状态的正负两个极端大幅摇摆。
熬夜让人疲累，记性变差。阿兹海默症也可能与睡眠不足有关。
同时睡眠不足也会给身体带来各种危害，全面冲击心血管系统，走向糖尿病与肥胖，影响生殖系统，免疫力低下并导致癌症，甚至可能会影响基因和 DNA。&lt;/p&gt;
&lt;p&gt;书中前两部分介绍什么是睡眠，以及为什么要睡觉。
读后可能就会对“&lt;strong&gt;人类是唯一会在无益的情况下故意剥夺自己睡眠的生物&lt;/strong&gt;”而感到不可思议。&lt;/p&gt;
&lt;h2 id="第三部--第四部--尾声"&gt;第三部 + 第四部 + 尾声&lt;/h2&gt;
&lt;p&gt;第三部分作者指出梦有自己的特殊作用，是一种夜间治疗，可以抚平伤痛、解读表情，是我们需要的生存能力。&lt;/p&gt;
&lt;p&gt;作者反对弗洛伊德对梦的观点，指出梦的精神分析方法无法被科学证实也无法被证伪。&lt;/p&gt;
&lt;p&gt;作者认为抚平伤痛的并不一定是时间，而是花在做梦的睡眠时间。
快速眼动睡眠时做的梦会记住重要的经验细节，并与现存记忆整合，也会忘记，消除内心深处先前包裹在记忆外的痛苦情绪负荷。
只有特定内容的梦，才能让人从痛苦中解脱。&lt;/p&gt;</description></item><item><title>R语言实战：处理缺失数据的高级方法</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-24-r-in-action-missing-data/</link><pubDate>Mon, 24 May 2021 20:56:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-24-r-in-action-missing-data/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍处理缺失值的几种常见方法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(VIM)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(mice)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="处理缺失值的步骤"&gt;处理缺失值的步骤&lt;/h2&gt;
&lt;p&gt;完全随机缺失 (MCAR)&lt;/p&gt;
&lt;p&gt;随机缺失 (MAR)&lt;/p&gt;
&lt;p&gt;非随机缺失 (NMAR)&lt;/p&gt;
&lt;h2 id="识别缺失值"&gt;识别缺失值&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(sleep, pakcage&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;VIM&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;列出没有缺失值的行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sleep&lt;span style="color:#a6e22e"&gt;[complete.cases&lt;/span&gt;(sleep),]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
2 1e+00 7e+00 6 2.0 8 4 42 3 1 3
5 3e+03 5e+03 2 1.8 4 69 624 3 5 4
6 1e+01 2e+02 9 0.7 10 27 180 4 4 4
7 2e-02 3e-01 16 3.9 20 19 35 1 1 1
8 2e+02 2e+02 5 1.0 6 30 392 4 5 4
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;列出至少有一个缺失值的行&lt;/p&gt;</description></item><item><title>视界：IFShub - 开展IFS试验的新方式</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-29-view-ifshub-a-new-way-to-work-with-ifs-experiments/</link><pubDate>Sun, 16 May 2021 18:16:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-29-view-ifshub-a-new-way-to-work-with-ifs-experiments/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Paul Burton, Manuel Martins, Stephan Siemen, Michael Sleigh. IFShub: a new way to work with IFS experiments. ECMWF Newsletter Number 167 - Spring 2021. 2021.04. &lt;a href="https://www.ecmwf.int/en/newsletter/167/computing/ifshub-new-way-work-ifs-experiments"&gt;https://www.ecmwf.int/en/newsletter/167/computing/ifshub-new-way-work-ifs-experiments&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文正文部分翻译自 ECMWF Newsletter Spring 2021 中由 Paul Burton 等人撰写的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/167/computing/ifshub-new-way-work-ifs-experiments"&gt;IFShub: a new way to work with IFS experiments&lt;/a&gt;》。
翻译底稿来自谷歌翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;在任何给定时间，大约有 500 个 ECMWF 的 Integrated Forecasting System (IFS) 的实验在同时运行，包括中心以及我们的会员国和合作国用户的研究工作。
需要大量不同的定制工具，以使研究人员能够管理实验工作负载。
已有不同的应用程序可以用来准备和提交实验，监视运行工作的状态，管理在整个生命周期中存储在我们的气象归档 (MARS) 中的结果数据，并科学地分析和评估结果。
这些工具大多数是桌面应用程序，有些具有 GUI 界面，并且所有工具都是由不同的团队彼此独立开发的。
每个工具使用的编程语言，界面，设计，依赖库和体系结构都是各不相同。&lt;/p&gt;
&lt;p&gt;特别地，PrepIFS 是研究人员用来创建，检查和存储实验配置，并将这些实验提交给高性能计算设备 (high-performance computing facility, HPCF) 的工具。
PrepIFS 已经使用了几十年，并且经受了时间的考验，但是近年来，它已经出现了一些可维护性问题。
现在，该应用程序几乎是 ECMWF 仅有的使用 Java 编写的工具，而中心几乎没有 Java 的专业知识。
这是因为近年来几乎所有开发都已转移到 Python 和 C++，而 IFS 本身仍主要使用 Fortran 编写。
此外，开发 IFS 的科学家在创建用户界面方面的专业知识有限，并且在该领域具有丰富经验的应用程序开发人员可以更好地完成此任务。
这类可维护性问题自然会导致可用性问题，因为不必要的改进和错误修复变得非常耗时而无法实施，开发工作必须降至最低限度。
PrepIFS 还使用定制语言来定义管理有效配置的逻辑规则，从而难以实施新的或改进的规则。&lt;/p&gt;</description></item><item><title>基于消息通讯的数值预报业务系统运行监视和分析技术研发</title><link>https://blog.perillaroc.wang/post/2021/publication/report-operation-monitoring-and-analysis-technology-based-on-message-communication/</link><pubDate>Sat, 15 May 2021 17:29:20 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/publication/report-operation-monitoring-and-analysis-technology-based-on-message-communication/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本技术报告于 2021 年 1 月撰写，并获 2020 年数值预报中心优秀技术报告二等奖&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题目：基于消息通讯的数值预报业务系统运行监视和分析技术研发&lt;/p&gt;
&lt;p&gt;主要撰写人：王大鹏&lt;/p&gt;
&lt;p&gt;中国气象局数值预报中心，北京，100081&lt;/p&gt;
&lt;h2 id="摘要"&gt;摘要&lt;/h2&gt;
&lt;p&gt;为了向数值预报业务系统产品制作模块提供有效的数据生成通知机制，同时实现对任务运行状态变化信息的实时保存，本文基于消息中间件技术，研发数值预报业务系统运行监视和分析技术，结合国家气象中心统一监控平台，设计并实现NWPC消息平台系统，设计适合数值预报业务系统的产品消息和运行状态变化消息，实现适合不同应用需求的消息发送和存储检索技术，实时发送GRAPES模式业务系统的GRIB2产品生成消息，实现标准时间和运行状态分析等统计分析算法，通过实时检索和实时绘图等技术实现可视化面板。NWPC消息平台系统已在中国气象局数值预报中心的GRAPES数值预报模式业务系统中得到应用，为业务系统维护人员提供直观的系统运行情况和统计信息，为保障数值预报业务系统稳定运行提供参考数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键字&lt;/strong&gt;：数值预报业务系统；消息中间件；运行监视；统计分析；GRAPES&lt;/p&gt;
&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;近年来，中国气象局数值预报中心已通过自主研发建立GRAPES数值天气预报业务体系，实现从区域3-10km到全球25-50km分辨率的确定性和集合预报系统[1]。数值天气预报业务系统通常由多个步骤构成，一般分为资料前处理、模式计算和产品后处理等三个步骤[2]。数值预报中心大部分业务系统都由两个子系统构成，其中模式积分子系统包括资料前处理和模式计算两个步骤，而产品制作步骤在单独的产品后处理系统中。随着气象大数据云平台“天擎”投入业务试运行[3]，数值预报中心正在将部分产品制作任务迁移到气象大数据云平台的加工流水线上，但缺乏有效的数据驱动手段。目前正在开发的世界气象中心网站产品制作系统使用基于文件的方式判断模式产品生成情况，数据检测模块需要不断扫描文件目录，判断某个时效的文件是否生成，存在很多不足。模式系统生成的数据文件产品数量较多，文件名缺乏统一规范，编写数据检测模块程序的工作量大，容易出错，不便于扩展。同时，不同系统间无法共享模式产品生成信息。所以，需要一种有效的产品生成通知机制，为产品后处理系统提供新的数据驱动手段。&lt;/p&gt;
&lt;p&gt;气象领域已广泛使用工作流软件对数值预报业务系统进行调度监控，包括欧洲中期数值预报中心开发的SMS[4, 5]和ecFlow[6, 7]，以及新西兰气象局、英国气象局联合开发的Cylc[8]。数值预报中心已于2017年建立基于SMS的数值预报业务移动监控平台[9]，并在2018年随着业务调度软件升级为ecFlow，将平台升级为数值预报业务系统运行监视平台[10]。该平台定时获取ecFlow中所有任务的运行状态，并在发现异常时发送微信报警。但该平台仅能发现运行出错类型的故障，尚未支持其他类型的故障，比如任务运行超时等。实现更复杂故障的自动报警，需要结合历史运行数据，根据当前时次任务状态的时间序列数据进行分析，这就要求保留所有任务运行状态信息。当前使用ecFlow调度的业务系统共有将近10万个任务，如果保存定时获取的所有运行状态，会带来海量的日志数据，不方便存储和分析。绝大部分情况下，数值预报业务系统的任务在同一天中只会运行一次，如果使用任务运行状态变化数据代替任务运行状态数据，会显著减少需要存储的数据量，也使得分析历史数据成为可以实时运行的任务。数值预报中心已研发SMS日志分析工具，获取任务的历史运行状态信息[11]。ecFlow是SMS的升级版，有相似的日志结构。该研究只针对离线数据统计，适合从日志文件中批量读取日志条目进行分析。如果想要实时发现故障，需要及时保存任务状态变化信息并提供实时查询能力。&lt;/p&gt;
&lt;p&gt;消息中间件是一种用于数据通讯的中间件技术，可以用来实现不同组件之间的高效消息数据传递，已在气象领域获得广泛应用[12-18]。本文基于消息中间件技术，研究数值预报业务系统运行监视和分析技术，结合国家气象中心统一监控平台，研发数值预报中心消息平台系统，设计适合数值预报业务系统的产品消息和运行状态变化消息，实时发送GRAPES模式业务系统的GRIB2产品生成消息，为产品后处理系统提供消息驱动。研发面向消息数据的发送、存储、统计分析和可视化展示技术，为业务系统维护人员提供直观的系统运行情况和统计信息，为保障数值预报业务系统稳定运行提供参考数据。&lt;/p&gt;
&lt;h2 id="1-总体设计"&gt;1 总体设计&lt;/h2&gt;
&lt;h3 id="11-系统架构"&gt;1.1 系统架构&lt;/h3&gt;
&lt;p&gt;NWPC消息平台系统采用分层结构设计，分为持久层，服务层和应用层，如图 1-1 所示。
持久层保存消息数据和统计分析算法得到的分析数据，采用Elasticsearch数据库保存JSON格式文档。&lt;/p&gt;
&lt;p&gt;服务层是系统的核心部分。任务脚本直接或通过代理服务组件向消息中间件发送消息数据；消息中间件组件包含NWPC消息平台使用的RabbitMQ和国家气象中心监控平台使用的Kafka；消息存储组件从消息中间件中读取数据并批量发送给数据库；统计分析组件包含标准时间算法和运行状态分析算法，从数据库中读取消息，并将结果保存到数据库中；可视化服务组件实时从数据库中检索数据，并为可视化面板提供实时绘图服务。&lt;/p&gt;
&lt;p&gt;应用层为用户提供可视化和报警功能。NWPC消息平台可视化面板实时展示产品生成时间，同时也提供对历史数据的统计分析功能；NWPC消息平台对接气象中心综合业务感知平台，关键业务信息监视页面展示GRAPES模式产品生成情况，在产品生成延迟时会发送报警短信。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/publication/report/nwpc-message/system-architecture-v2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图 1-1&lt;/strong&gt; &lt;em&gt;NWPC消息平台系统架构，其中虚线框组件是平台对接的外部系统&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="12-系统功能"&gt;1.2 系统功能&lt;/h3&gt;
&lt;p&gt;NWPC消息平台系统功能主要分为消息发送、消息存储、统计分析、可视化展示和监控报警等五个部分。具体功能如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;消息发送：在数值预报业务系统脚本中，按照消息数据的用途，使用命令行程序通过多种方式向消息中间件发送消息数据。对于运行在HPC内部网络的任务，通过代理服务向气象局内网中的消息中间件发送消息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;消息存储：从多种消息中间件中接收消息数据，并进行预处理，按照不同的索引规则，保存到Elasticsearch数据库中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;统计分析：使用自助法求置信区间等技术，对存储在数据库中的产品消息数据进行分析，得到产品生成的标准时间段，结果以JSON格式文档形式保存到数据库中；利用确定有限状态自动机等技术，对运行状态序列数据进行分析，得到任务运行的起止时间和运行时长。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可视化展示：实时展示GRAPES系列模式各个时次逐时效产品的生成时间，支持对历史生成时间的查询，根据用户操作在线展示多种统计图形。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;监控报警：对接国家气象中心的综合业务感知平台，实时发送GRAPES模式GRIB2产品生成消息，为各个时次的产品生成时间设置阈值，当产品生成晚于阈值时间时，向值班人员发送产品生成延迟报警短信。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="13-消息设计"&gt;1.3 消息设计&lt;/h3&gt;
&lt;p&gt;为了保证整个平台的统一性，NWPC消息平台中的所有消息都表示某种与数值预报业务系统运行相关的事件，并基于JSON格式设计事件消息规范。本研究使用两种消息规范类型：符合国家气象中心统一业务监控平台规范的数值预报产品消息，以及一种适用性更强的通用消息规范。&lt;/p&gt;
&lt;h4 id="131-气象中心消息"&gt;1.3.1 气象中心消息&lt;/h4&gt;
&lt;p&gt;国家气象中心已建立统一业务监控平台，基于消息中间件Kafka实现消息系统，制定消息数据规范《国家气象中心消息体设计方案V1.4》。本文根据该规范设计数值预报产品消息格式，表示GRAPES模式原始分辨率GRIB2产品已生成。消息示例如图 1-2 所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/publication/report/nwpc-message/nmc-message-2021.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图 1-2&lt;/strong&gt; &lt;em&gt;适用于国家气象中心监控平台的数值预报产品消息格式，表示GRAPES GFS系统2020年12月30日00时次的210时效GRIB2产品在北京时间2020-12-30 13:35:07生成。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;其中source字段表示生成产品的模式系统，resultDesc字段由两个字段构成，startTime表示起报时间，forecastTime表示预报时效。&lt;/p&gt;
&lt;h4 id="132-通用消息规范"&gt;1.3.2 通用消息规范&lt;/h4&gt;
&lt;p&gt;本研究基于JSON格式设计一种通用的事件消息规范，具有极强的灵活性，可以根据不同的监控需求进行扩展。&lt;/p&gt;
&lt;p&gt;通用事件消息包含三个固定字段和一个可变的复合字段。其中app表示发出事件的应用名，type表示事件类型，time表示事件发出时的时间戳，data是键值对形式的数据字段，记录与事件相关的数据。为了保持消息的一致性，每种类型的消息都需要预先定义数据字段。但每个事件消息不一定包含该类型消息所有的数据字段，可以从备选字段中选择需要的字段。也就是说，每类消息还可能有子类型。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/publication/report/nwpc-message/event-message.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图 1-3&lt;/strong&gt; &lt;em&gt;通用事件消息结构&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;事件消息数据字段的一个重要组成部分就是事件的状态。本研究借鉴ecFlow的节点运行状态，为所有事件消息定义统一的事件状态，包含7种状态，如表 1所示。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;表 1&lt;/strong&gt; &lt;em&gt;事件状态表&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;状态名&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;unknown&lt;/td&gt;
					&lt;td&gt;未知状态，默认值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;complete&lt;/td&gt;
					&lt;td&gt;完成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;queued&lt;/td&gt;
					&lt;td&gt;排队&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;aborted&lt;/td&gt;
					&lt;td&gt;出错&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;submitted&lt;/td&gt;
					&lt;td&gt;提交&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;active&lt;/td&gt;
					&lt;td&gt;运行&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;suspended&lt;/td&gt;
					&lt;td&gt;挂起&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;基于上述通用事件消息规范，本研究设计两类事件消息：产品消息和运行状态变化消息。&lt;/p&gt;</description></item><item><title>视界：ECMWF在线-社区、协作和赋权</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-28-view-ecmwf-online-community-collaboration-and-empowerment/</link><pubDate>Tue, 11 May 2021 21:54:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-28-view-ecmwf-online-community-collaboration-and-empowerment/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Helen Setchell, Sylvie Lamy-Thépaut, Andrew Brady. ECMWF online – community, collaboration and empowerment. ECMWF Newsletter Number 167 - Spring 2021, 2021.4. &lt;a href="https://www.ecmwf.int/en/newsletter/167/computing/ecmwf-online-community-collaboration-and-empowerment"&gt;https://www.ecmwf.int/en/newsletter/167/computing/ecmwf-online-community-collaboration-and-empowerment&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;以下正文部分翻译自 ECMWF Newsletter Number 167 的文章《ECMWF online – community, collaboration and empowerment》。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;网络使全球合作，可以促进数值天气预报的发展，并使我们能够分发我们的产品。
我们致力于不断开发和完善 ECMWF web，这是我们与世界相连的在线界面。
目的是支持 ECMWF 战略，并响应技术以及用户的行为和需求变化。
通过构建有用且可用的 ECMWF web，我们为授权用户的在线社区提供了协作和分享知识的场所。
通过用户友好和直观的在线界面，他们可以有效地自助使用 ECMWF 产品和服务。&lt;/p&gt;
&lt;p&gt;自从我们在 ECMWF 中对 Web 开发的最近更新 (Setchell，2018) 以来，我们已经对 Web 中那些带来最大价值和最常使用的领域进行了重大更新。
我们已经通过新的经过改进的图表浏览器免费提供了使用开放许可证 (CC-BY-4.0) 协议的实时图表，并且改善了交互式在线图表 ecCharts 的性能。
将来，用户还可以期望看到按需绘制的观测统计数据。&lt;/p&gt;
&lt;p&gt;对于那些想尝试数据的人，我们创建了新的在线 “集线器 (hubs)”。
我们还开始开发新的数据浏览器，以使我们的数据更易于发现，选择和使用。&lt;/p&gt;
&lt;p&gt;我们通过新闻，博客，社交媒体，出版物，员工资料，在线活动，eLearning 课程，支持门户，文档和论坛，提供更多在线参与和知识分享的机会，从而发展了利益相关者和用户的在线社区。&lt;/p&gt;</description></item><item><title>CloudWS 2021：Setting the scene</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-10-cloud-ws-2021-002-setting-the-scene/</link><pubDate>Mon, 10 May 2021 22:07:37 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-10-cloud-ws-2021-002-setting-the-scene/</guid><description>&lt;p&gt;本文&lt;strong&gt;正文&lt;/strong&gt;部分来自 ECMWF 于 2021 年 2 月召开的 &lt;strong&gt;Virtual workshop: Weather and climate in the cloud&lt;/strong&gt; (Cloud-WS 2021) 中的如下演讲：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Setting the Scene: Weather and Climate in the cloud&lt;/p&gt;
&lt;p&gt;or why are we here?&lt;/p&gt;
&lt;p&gt;by Stephan Siemen&lt;/p&gt;
&lt;p&gt;at Cloud-WS 2021&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;设置场景&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="背景"&gt;背景&lt;/h3&gt;
&lt;p&gt;云计算变得很重要&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/cloud-ws-2021/02/p9.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图片来自幻灯片&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;持续增长的数据量挑战&lt;/p&gt;
&lt;p&gt;如何能确保用户可以探索全部的潜力&lt;/p&gt;
&lt;h3 id="解决方法将处理靠近数据"&gt;解决方法：将处理靠近数据&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/cloud-ws-2021/02/p10.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图片来自幻灯片&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;云服务&lt;/strong&gt;：方便访问和使用数据，Copernicus CDS &amp;amp; ADS&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;机器学习数据分析环境&lt;/strong&gt;：Jupyter Notebook，可以在笔记本上进行开发，在服务器上运行&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;服务容器化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;存储解决方案&lt;/strong&gt;：对象存储 ceph，快速访问数据&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;向公有云用户提供预报&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;探索未来计算&lt;/strong&gt;，Destination Earth&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;H2020项目&lt;/strong&gt;，探索分布处理&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;创建社区云&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="研讨会主题"&gt;研讨会主题&lt;/h3&gt;
&lt;p&gt;Day 1：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;云提供商&lt;/li&gt;
&lt;li&gt;云应用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Day 2：&lt;/p&gt;</description></item><item><title>读书笔记：枪炮，病菌与钢铁</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-06-book-guns-germs-steel/</link><pubDate>Sun, 09 May 2021 10:22:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-06-book-guns-germs-steel/</guid><description>&lt;p&gt;枪炮、病菌与钢铁：人类社会的命运&lt;/p&gt;
&lt;p&gt;原作名：Guns, Germs and Steel: The Fates of Human Societies&lt;/p&gt;
&lt;p&gt;本文记录 4 月在读书小组内发的 4 段读书笔记。&lt;/p&gt;
&lt;h2 id="第一部分"&gt;第一部分&lt;/h2&gt;
&lt;p&gt;1-3 章&lt;/p&gt;
&lt;p&gt;作者在第一章中介绍从人类诞生到公元前 11000 年左右的历史，这一年代大致相当于世界上一些地区村社生活的开始，是用以比较不同大陆的历史发展的合适起点。
作者不认同关于美洲大型动物灭绝的气候理论和关于澳大利亚/新几内亚大型动物灭绝的气候理论，认为是由人类的捕猎行为导致它们的灭绝，而大型动物的缺失也对其后的人类历史带来了严重的后果。
（第二部分会介绍到，大型哺乳动物是重要的蛋白质来源，可以用于人力无法实现的耕地，可以用于长途运输和战争）。
一个被送回到公元前 11000 年的观察者可能不会预测到哪个大陆上的人类社会会发展最快，但他可以提出充分的理由说明任何一个大陆都有这样的机会。
事实上，从那时起，某些大陆上的族群已经比其他大陆上的族群领先一步或处于明显优势。&lt;/p&gt;
&lt;p&gt;第二章以波利尼西亚群岛为例简要地考察岛屿环境在较小的时空范围内对历史的影响。
莫里奥里人被毛利人征服可以看成是一个短暂的小规模的自然实验，测试环境影响人类社会的程度。
莫里奥里岛无法种植热带植物，人们只能回归狩猎采集生活，不能生产农作物，无法养活专职人员，例如手艺人、军队、行政人员和首领等。没有其它岛屿可以移民，放弃战争，不好战，人口受限，缺乏强力的领导和组织。
从而被不到自己人口总数一半的毛利入侵者而轻易征服。&lt;/p&gt;
&lt;p&gt;在波利尼西亚群岛之间，至少有 6 种环境可变因素促成了波利尼西亚社会之间的这些差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;岛屿气候，气温和降水量；&lt;/li&gt;
&lt;li&gt;地质类型，土地是否肥沃；&lt;/li&gt;
&lt;li&gt;海洋资源，是否有丰富的海产；&lt;/li&gt;
&lt;li&gt;面积，容纳人口的数量；&lt;/li&gt;
&lt;li&gt;地形的破碎，地形是否会阻隔人员行走往来；&lt;/li&gt;
&lt;li&gt;隔离程度，与其它岛屿的距离。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于现存人类社会的与环境有关的差异性问题，波利尼西亚为我们提供了一个令人信服的例证。&lt;/p&gt;
&lt;p&gt;第三章以印加帝国末代皇帝被西班牙入侵者俘虏的历史，介绍来自不同大陆的各民族之间的冲突。
试图分析为什么是西班牙人俘虏了印加皇帝，而不是反过来。
直接原因包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以枪炮、钢铁武器和马匹为基础的军事技术；&lt;/li&gt;
&lt;li&gt;欧亚大陆的传染性流行病；&lt;/li&gt;
&lt;li&gt;欧洲的航海技术；&lt;/li&gt;
&lt;li&gt;欧洲国家集中统一的行政组织和文字。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;即便现在没有历史上那样的征服战争，上述这些直接原因在当今社会也有所体现，比如我们在强调自主创新和推进重点领域攻克卡脖子技术，比如最近我们在大力推广接种新冠疫苗，比如我们在面对新冠疫情时所展现出来的动员能力等等。
但这些不是终极原因，因为正是终极原因产生了近似原因，产生了实际结果。
为什么直接优势在欧洲一边而不在新大陆一边？
后续章节会讨论这个问题。&lt;/p&gt;
&lt;h2 id="第二部分"&gt;第二部分&lt;/h2&gt;
&lt;p&gt;4-10 章&lt;/p&gt;
&lt;p&gt;介绍粮食生产也就是农业对文明发展的重要性。
作者认为粮食生产是枪炮、病菌和钢铁发展的一个先决条件。
在粮食生产上具有领先优势的那些地区里的族群，在通往枪炮、病菌和钢铁的道路上也取得了领先的优势。
作者继续分析为什么会选择种田而不是狩猎采集。
粮食生产制度的渐次形成是许多关于时间和劳力分配的不同决定积累的结果。
在地球上大多数适于粮食生产的地区，狩猎采集族群只能有两种命运：要么他们被邻近的粮食生产者所取代；要不他们为了生存只有采纳粮食生产的办法。
作者接着介绍如何古人如何在无意识中驯化了植物。
到了罗马时代，今天的几乎所有作物都已在世界上的某个地方得到驯化。
作者进一步分析某些地区没有发展农业到底是当地人的问题，还是当地可以得到的野生植物的问题。
通过多个示例说明农业发展的差异与族群本身没有任何关系，而是与生物区系和环境有着最密切的关系。&lt;/p&gt;
&lt;p&gt;对于驯服动物的困难，作者则借用《安娜 卡列尼娜》著名的第一句话来说明。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;幸福的家庭都是幸福的；不行的家庭各有各的不幸。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;任何一点不满足条件都会导致驯化失败，即使是现在也无法比古代人驯化更多的大型哺乳动物。
欧亚大陆以外没有大型哺乳动物被驯化的原因不在当地的人，而在于当地现有的哺乳动物本身。
最后，作者介绍地理因素对农业传播的影响，指出传播速度的差异只是欧亚大陆轴线走向与美洲或非洲大陆轴线相比较的结果，而不是欧亚大陆早期农民具有过人的智慧。&lt;/p&gt;
&lt;h2 id="第三部分"&gt;第三部分&lt;/h2&gt;
&lt;p&gt;11-14 章&lt;/p&gt;</description></item><item><title>GRIB笔记：cfgrib加载GRIB2要素场速度测试</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-08-grib-notebook-cfgrib-speed/</link><pubDate>Sat, 08 May 2021 23:03:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-08-grib-notebook-cfgrib-speed/</guid><description>&lt;p&gt;cfgrib 是由 ECMWF 基于 eccodes-python 库开发的 GRIB 格式 Python 解码库，提供兼容 xarray 的接口，是 xarray 中默认的 GRIB 解码库。&lt;/p&gt;
&lt;p&gt;笔者在去年开始尝试使用 cfgrib，发现该库从 GRIB 文件中加载要素场的速度不如直接使用 eccodes-python 库读取要素场。
随后笔者仿照 cfgrib 开发了另一个 GRIB 格式的 xarray 接口，集成在 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库中。&lt;/p&gt;
&lt;p&gt;本文延续去年的工作，测试对比使用 cfgrib 库和 eccodes-python (使用 nwpc-data 封装的接口) 加载单个 GRIB 2 要素场的速度，尝试对背后的原因进行分析。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文仅单次运行测试代码，得到的时间不够精确&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="测试-1文件中查找要素场"&gt;测试 1：文件中查找要素场&lt;/h2&gt;
&lt;p&gt;从 2021 年 1 月 1-7 日 00 时次的 GRAPES GFS 的 GRIB 2 产品 024 时效文件中抽取 850hPa 的假相当位温 (papt) 并求和。&lt;/p&gt;
&lt;p&gt;测试环境：CMA-PI 登录节点 + 自行安装的 Python 版本。&lt;/p&gt;</description></item><item><title>R语言实战：分类</title><link>https://blog.perillaroc.wang/post/2021/05/2021-05-01-r-in-action-classify/</link><pubDate>Sat, 01 May 2021 15:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/05/2021-05-01-r-in-action-classify/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍有监督机器学习领域中四种可用于分类的方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;逻辑回归&lt;/li&gt;
&lt;li&gt;决策树&lt;/li&gt;
&lt;li&gt;随机森林&lt;/li&gt;
&lt;li&gt;支持向量机&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(glue)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;威斯康星州乳腺癌数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;loc &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://archive.ics.uci.edu/ml/machine-learning-databases/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;breast-cancer-wisconsin/breast-cancer-wisconsin.data&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;url &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;glue&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;{loc}{ds}&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载网络数据，并设置列名。
数据中的缺失数据用 &lt;code&gt;?&lt;/code&gt; 表示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;breast &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read.table&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; url,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sep&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;,&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; header&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; na.strings&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;?&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;(breast) &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ID&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;clumpThickness&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sizeUniformity&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;shapeUniformity&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;maginalAdhesion&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;singleEpithelialCellSize&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bareNuclei&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;blankChromatin&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;normalNucleoli&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;mitosis&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;class&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(breast)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; ID clumpThickness sizeUniformity shapeUniformity maginalAdhesion
1 1000025 5 1 1 1
2 1002945 5 4 4 5
3 1015425 3 1 1 1
4 1016277 6 8 8 1
5 1017023 4 1 1 3
6 1017122 8 10 10 8
 singleEpithelialCellSize bareNuclei blankChromatin normalNucleoli
1 2 1 3 1
2 7 10 3 2
3 2 2 3 1
4 3 4 3 7
5 2 1 3 1
6 7 10 9 7
 mitosis class
1 1 2
2 1 2
3 1 2
4 1 2
5 1 2
6 1 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;替换 &lt;code&gt;class&lt;/code&gt; 列&lt;/p&gt;</description></item><item><title>五一劳动节快乐</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-30-happer-labor-day/</link><pubDate>Fri, 30 Apr 2021 23:17:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-30-happer-labor-day/</guid><description>&lt;p&gt;又到了一年一度的五一假期，虽然调休拼凑的方式引起很大争议，但毕竟有长达五天的假期，考虑到春节期间倡导就地过年，也能理解政策制定者的良苦用心。&lt;/p&gt;
&lt;p&gt;五一期间我没有值班工作，所以希望我自己能利用这宝贵的五天时间好好思考下未来的工作，分析最近一段时间工作学习效率不高的原因，思考为什么我总会时不时陷入一种对未来的焦虑之中，并在不同的工作方向之间徘徊不定。&lt;/p&gt;
&lt;p&gt;未来首要的事情就是要应对外部环境的变化。
可能即将会到来的机构调整、职责变化和工作任务也许会对多年形成的工作习惯造成强烈的冲击。
如果应对不当，则很有可能会面临很长一段时间的调整期，工作效率将比现在更低。
我需要尽量避免陷入一种恶性循环的境地，尽快确立自己工作的核心目标，并围绕该目标来应对接下来的各种变革和挑战。&lt;/p&gt;
&lt;p&gt;虽然我在年初信誓旦旦地保证不再纠结运维工作，但我不得不承认在可以预见的将来，我的工作职责中还将一直保留运维相关部分。
为了给诸如研发支撑等其它工作留下充足的时间，必须提高业务系统建设和运维的工作效率，而相关技术开发同样需要投入大量的精力。
这就又回到一个我一直想要脱离却一直在经历的情况：将时间过多地花费在运维技术开发中，而在其它更能体现价值的支撑技术开发工作上没有做出成绩。
我对未来的焦虑和在不同工作方向之间的摇摆很大程度上是因为无法摆脱这种两难的境地。&lt;/p&gt;
&lt;p&gt;不过正如 2020 年 11 月 24 日在全国劳动模范和先进工作者表彰大会上的讲话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1950 年党和国家首次表彰劳动模范 70 年来，在党的领导下，我国工人阶级和广大劳动群众与祖国同成长、与时代齐奋进，奏响了“咱们工人有力量”的主旋律，各条战线英雄辈出、群星灿烂。
特别是进入新时代以来，我国工人阶级和广大劳动群众在实现中国梦伟大进程中拼搏奋斗、争创一流、勇攀高峰，为决胜全面建成小康社会、决战脱贫攻坚发挥了主力军作用，用智慧和汗水营造了劳动光荣、知识崇高、人才宝贵、创造伟大的社会风尚，谱写了“中国梦·劳动美”的新篇章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;作为劳动人民的一员，我相信自己能克服困难找到未来的方向，也相信自己能努力工作为科技发展做出自己的贡献。&lt;/p&gt;
&lt;p&gt;劳动人民最光荣！&lt;/p&gt;</description></item><item><title>视界：ECMWF走向开放科学</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-29-veiw-towards-open-science/</link><pubDate>Thu, 29 Apr 2021 21:59:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-29-veiw-towards-open-science/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Nikolaos Mastrantonas, Milana Vučković. Towards open science. ECMWF Newsletter Number 167 - Spring 2021. 2021.04. &lt;a href="https://www.ecmwf.int/en/newsletter/167/news/towards-open-science"&gt;https://www.ecmwf.int/en/newsletter/167/news/towards-open-science&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文正文部分翻译自 ECMWF Newsletter Spring 2021 中由 Nikolaos Mastrantonas 等人撰写的新闻稿《&lt;a href="https://www.ecmwf.int/en/newsletter/167/news/towards-open-science"&gt;Towards open science&lt;/a&gt;》。
翻译底稿来自谷歌翻译，并根据笔者的个人理解略有修改。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;在最近论文发表之后，本文提出了我们在 “开放科学 (open science)” 的指引下采取的一些补充行动，使感兴趣的用户和研究人员可以更容易地获取该工作。&lt;/p&gt;
&lt;h3 id="共享科学"&gt;共享科学&lt;/h3&gt;
&lt;p&gt;科学出版物对于扩大我们的知识至关重要。
然而，独立出版物 (stand-alone pulication) 阻止了读者的许多方面的工作。
这就是为什么许多研究人员和研究机构转向开放科学的原因。
这意味着他们将论文的附加材料进行公开发布，例如数据和开发的工具。&lt;/p&gt;
&lt;p&gt;最近有关地中海极端降水的论文 (&lt;a href="https://doi.org/10.1002/joc.6985"&gt;https://doi.org/10.1002/joc.6985&lt;/a&gt;) 也遵循类似的路线。
这项工作分析了整个地中海区域极端降水事件的时空特征，并量化了它们与整个区域内大规模大气环流的联系。
考虑到它可能引起许多研究人员以及我们会员国和合作国用户的兴趣，我们的想法比 (开放访问) 同行评审的出版物走得更远。
在迈向开放科学的过程中，这项工作使用了可自由访问的数据集和软件，并在线提供了所有后处理数据和为分析而开发的脚本。&lt;/p&gt;
&lt;h3 id="动机"&gt;动机&lt;/h3&gt;
&lt;p&gt;这些附加举措背后的动机有三方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共享工具和数据可以支持针对类似主题的研究&lt;/li&gt;
&lt;li&gt;我们还希望鼓励更多的科学家采用类似的方法，并加强地球科学界在开放性和可访问性科学领域已经做出的杰出努力。&lt;/li&gt;
&lt;li&gt;通过将工作公开发布，我们希望从感兴趣的用户那里获得有价值的反馈。该反馈可以帮助进一步改进所使用的实践并优化分析&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简而言之，对开放科学的每项贡献都支持科学界的集体努力，并为改善个人技能和能力提供了机会。&lt;/p&gt;
&lt;h3 id="使用的数据和工具"&gt;使用的数据和工具&lt;/h3&gt;
&lt;p&gt;作为哥白尼计划的一部分，ECMWF 提供了 ERA5，这是最新最先进的高分辨率再分析数据集。
该项分析作为对地中海极端降水研究的一部分，使用了 ERA5 再分析数据集，可在 Copernicus Climate Data Store 中免费获得。&lt;/p&gt;
&lt;p&gt;我们还使用了 Python 软件，一种免费的开源编程语言，拥有广泛的开发人员社区。
所有用于处理数据和创建图形的脚本都是在 Jupyter Notebook 环境中使用 Python 编写的，Notebook 脚本易于他人使用，并提供了将代码与图形和说明文字一起提供的机会。&lt;/p&gt;</description></item><item><title>产品生成时间聚类</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-25-nwpc-message-production-time-clustering/</link><pubDate>Mon, 26 Apr 2021 00:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-25-nwpc-message-production-time-clustering/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;数值预报业务系统运维的终极目标之一就是保障产品的按时分发。
这就涉及到如何界定产品生成时间是否正常，使用什么样的标准来判断产品生成时间延迟。
目前我们在实践中通常使用一个固定的时间阈值。
但为了获取更精确的提供产品服务的时间，需要对历史数据进行统计分析。&lt;/p&gt;
&lt;p&gt;本文尝试采用聚类方法来判断产品生成是否延迟。
下面使用两种方法对产品生成时间进行聚类，对比不同聚类数目的分类结果。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;使用 NWPC 消息平台中 2020 年 10 月 1 日至 2021 年 3 月 31 日 GRAPES MESO 3KM 系统 036h 时效原始分辨率 GRIB2 数据的产品生成事件消息。&lt;/p&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-message-tool"&gt;nwpc-oper/nwpc-message-tool&lt;/a&gt; 库从 ElasticSearch 中检索并保存成 CSV 文件。&lt;/p&gt;
&lt;p&gt;使用 R 语言 &lt;code&gt;read.csv()&lt;/code&gt; 函数加载后数据类似：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; system stream type name start_time forecast_hour
1 grapes_meso_3km oper grib2 orig 2020-10-01 36
2 grapes_meso_3km oper grib2 orig 2020-10-02 36
3 grapes_meso_3km oper grib2 orig 2020-10-03 36
4 grapes_meso_3km oper grib2 orig 2020-10-04 36
5 grapes_meso_3km oper grib2 orig 2020-10-05 36
6 grapes_meso_3km oper grib2 orig 2020-10-06 36
 time event status
1 2020-10-01 05:40:34 storage Complete
2 2020-10-02 05:35:50 storage Complete
3 2020-10-03 05:34:55 storage Complete
4 2020-10-04 05:39:35 storage Complete
5 2020-10-05 06:57:51 storage Complete
6 2020-10-06 05:39:47 storage Complete
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对数据进行处理，计算产品生成时间 &lt;code&gt;time&lt;/code&gt; 与起报时次 &lt;code&gt;start_time&lt;/code&gt; 的时间差值，结果如下所示&lt;/p&gt;</description></item><item><title>R语言实战：聚类</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-21-r-in-action-chap16-clustering/</link><pubDate>Wed, 21 Apr 2021 22:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-21-r-in-action-chap16-clustering/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;层次聚类&lt;/strong&gt;：hierarchical agglomerative clustering&lt;/p&gt;
&lt;p&gt;每个观测值自成一类，每次两两合并，直到所有类被聚成一类&lt;/p&gt;
&lt;p&gt;常用方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单联动 single linkage&lt;/li&gt;
&lt;li&gt;全联动 complete linkage&lt;/li&gt;
&lt;li&gt;平均联动 average linkage&lt;/li&gt;
&lt;li&gt;质心 centroid&lt;/li&gt;
&lt;li&gt;Ward 方法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;划分聚类&lt;/strong&gt;：patitioning clustering&lt;/p&gt;
&lt;p&gt;指定类的个数K，随机分成K类，再重新形成聚合的类&lt;/p&gt;
&lt;p&gt;常用方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;K 均值 K-means&lt;/li&gt;
&lt;li&gt;围绕中心点的划分 PAM&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(flexclust)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(rattle)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="聚类分析的一般步骤"&gt;聚类分析的一般步骤&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;选择合适的变量&lt;/li&gt;
&lt;li&gt;缩放数据：标准化或其他方法&lt;/li&gt;
&lt;li&gt;寻找异常点：删掉异常点或者使用对异常值稳健的聚类方法&lt;/li&gt;
&lt;li&gt;计算距离&lt;/li&gt;
&lt;li&gt;选择聚类算法&lt;/li&gt;
&lt;li&gt;获得一种或多种聚类方法&lt;/li&gt;
&lt;li&gt;确定类的数目&lt;/li&gt;
&lt;li&gt;获得最终的聚类解决方案&lt;/li&gt;
&lt;li&gt;结果可视化&lt;/li&gt;
&lt;li&gt;解读类&lt;/li&gt;
&lt;li&gt;验证结果&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="计算距离"&gt;计算距离&lt;/h2&gt;
&lt;p&gt;欧几里得距离&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(nutrient, package&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;flexclust&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(nutrient, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; energy protein fat calcium iron
BEEF BRAISED 340 20 28 9 2.6
HAMBURGER 245 21 17 9 2.7
BEEF ROAST 420 15 39 7 2.0
BEEF STEAK 375 19 32 9 2.6
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;dist()&lt;/code&gt; 函数，默认返回下三角矩阵&lt;/p&gt;</description></item><item><title>一种封装CMADaaS MUSIC Python接口的方法</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-19-wrap-cmadaas-music-api/</link><pubDate>Wed, 21 Apr 2021 16:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-19-wrap-cmadaas-music-api/</guid><description>&lt;p&gt;本文介绍如何封装 CMADaaS MUSIC 的 Python SDK，提供更高层的数据检索 API 接口，将尽可能多的数据检索接口整合到少量的 Python 函数中。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;h3 id="前期工作"&gt;前期工作&lt;/h3&gt;
&lt;p&gt;我在 2019 年写过一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-25-cimiss-python-api/"&gt;改造CIMISS MUSIC接口的Python SDK&lt;/a&gt;》，文中指出当时该 SDK 存在的两个问题：不支持 Python 3；密码明文传输。&lt;/p&gt;
&lt;p&gt;最近才发现在 2020 年的更新版本中，MUSIC Python SDK 已完全解决这两个问题：发布支持 Python 3 的版本，并将密码替换为由一系列字符串计算得到的 MD5 值。
所以非常有必要对之前随意下的结论进行反思和纠正，尤其是对于频繁更新的软件库而言。&lt;/p&gt;
&lt;p&gt;本文介绍我最近正在进行的一些尝试，对 2019 年改造的 MUSIC SDK 库进行重新设计，提供更高层的数据检索 API 接口，将尽可能多的数据检索接口整合到少量的 Python 函数中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;该项目还在开发当中，仅针对感兴趣的资料，目标也不是覆盖全部检索接口。
另外，因账户权限问题，缺乏部分资料的访问权限，无法测试部分接口。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="music-接口简介"&gt;MUSIC 接口简介&lt;/h3&gt;
&lt;p&gt;CMADaaS 的 MUSIC 接口设计符合 2019 年 3 月发布的由 NMIC 制定的《气象数据服务接口规范（征求意见稿）》。&lt;/p&gt;
&lt;p&gt;来自上述接口规范文件中的几个接口定义示例：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;接口&lt;/th&gt;
					&lt;th&gt;用途&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getSurfEleByTime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间的地面资料检索接口&lt;/td&gt;
					&lt;td&gt;站点资料读取接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getUparEleInRectByTimeAndVertical&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间、垂直探测意义、经纬度范围的高空资料检索接口&lt;/td&gt;
					&lt;td&gt;站点资料读取接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getTyphByTimeRangeAndTyphGids&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间段、台风编号（国际）的检索台风资料接口&lt;/td&gt;
					&lt;td&gt;站点资料读取接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getNafpEleGridByTimeAndLevelAndValidtime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间、预报层次、预报时效的单场单要素检索接口&lt;/td&gt;
					&lt;td&gt;数值格点资料解析接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getNafpEleAtPointByTimeAndLevelAndValidtimeRange&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间范围、预报层次、预报时段、经纬度的时间序列检索接口&lt;/td&gt;
					&lt;td&gt;数值格点资料解析接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getRadaFileByTimeRange&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间段的雷达资料检索接口&lt;/td&gt;
					&lt;td&gt;文件类资料读取接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getSateFileByTime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间的卫星资料文件检索接口&lt;/td&gt;
					&lt;td&gt;文件类资料读取接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;getNafpFileByElementAndTime&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;指定时间、预报要素的数值预报文件读取检索接口&lt;/td&gt;
					&lt;td&gt;文件类资料读取接口&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;接口定义由 3 部分组成：&lt;/p&gt;</description></item><item><title>论文阅读：FV3GFS模式的Python封装</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-04-paper-mcgibbon-2021-fv3gfs-wrapper/</link><pubDate>Thu, 15 Apr 2021 22:08:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-04-paper-mcgibbon-2021-fv3gfs-wrapper/</guid><description>&lt;p&gt;fv3gfs-wrapper: a Python wrapper of the FV3GFS atmospheric model&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;McGibbon, J., Brenowitz, N. D., Cheeseman, M., Clark, S. K., Dahm, J., Davis, E., Elbert, O. D., George, R. C., Harris, L. M., Henn, B., Kwa, A., Perkins, W. A., Watt-Meyer, O., Wicky, T., Bretherton, C. S., and Fuhrer, O.: fv3gfs-wrapper: a Python wrapper of the FV3GFS atmospheric model, Geosci. Model Dev. Discuss. [preprint], &lt;a href="https://doi.org/10.5194/gmd-2021-22"&gt;https://doi.org/10.5194/gmd-2021-22&lt;/a&gt;, in review, 2021.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一篇投稿于 Geoscientific Model Development 的预印本论文，介绍使用 Python 对 FV3GFS 大气模式进行封装。
文中将 Fortran 模式拆解为多个可以封装成 API 接口的步骤，比如动力框架和物理过程，使用 Python 控制整个模式积分过程，为在积分过程中整合其它代码提供基础。&lt;/p&gt;</description></item><item><title>视界：推动数值预报进步的科技之人工智能和机器学习</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-09-view-driving-advancement-of-numerical-prediction-ai-and-ml/</link><pubDate>Fri, 09 Apr 2021 20:19:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-09-view-driving-advancement-of-numerical-prediction-ai-and-ml/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自《WMO Open Consultative Platform White Paper #1 - Future of weather and climate forecasting》中 3.2.4 Innovation through artificial intelligence and machine learning 章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文翻译自 WMO “天气气候预报未来” 白皮书的 3.2.4 章节。
底稿来自 Google 翻译。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;通过人工智能和机器学习进行创新&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;大数据广泛存在于当今生活的各个领域，为收集和处理观测数据（包括大量非常规数据）的新方法带来期望。
这为大力开展新的预报方法和应用带来了巨大的潜力。
在过去几年中，已经出现了基于 AI 和 ML 的预报，在这种发展趋势中，拥有良好 IT 资源的私营气象公司尤其引起了人们的兴趣。
这些新方法的研究和可操作性将在未来十年内加速发展，以前所未有的使用规模为服务提供新机会。
这些发展中有趣的一部分是通过众包 (crowdsourcing) 和非正式合作使公民科学和社区参与其中。
这些发展包括以下内容：&lt;/p&gt;
&lt;p&gt;对于过去受不可克服的数据处理挑战所限制的任务，人工智能方法提供了巨大的潜力。
新处理器技术和 AI 方法的结合，允许用于商业应用的大型并行数据处理，实现了天气和气候预测应用。&lt;/p&gt;
&lt;p&gt;AI 方法 (这里主要是 ML) 最大的潜力之一就是观测数据的预处理和预报模式输出的后处理。
在这些领域中，需要处理大量的异构数据，以识别数据质量，复杂的多元观测误差结构，识别因果关系模式以诊断模式误差的来源并提取可用于广泛应用的信息。
一些基于 AI 的系统已经显示出与非常短期的有限区域模式相比有竞争力的结果，并且在季节尺度上展示了一定的能力。
长期的历史观测数据记录，再分析和业务预报的可用性为从现有数据中学习以及推导智能分析方法以供业务使用提供了巨大的资源。
机器学习方法也为加速预报系统提供了机会，特别是在可以利用新数据源并将其与传统数据结合或对物理原理没有清晰了解的地方。&lt;/p&gt;
&lt;p&gt;机器学习的另一个巨大潜力在于合并不同的数据集，例如天气和社会经济数据，例如空中交通管理/来自机场的运行数据。
机器学习技术的使用可以在提高服务的准确性和自动化方面取得进步，包括在业务预报，决策支持，雷达活动，卫星应用，超本地预报 (hyperlocal forecasting)，基于影响的预测以及对预报员的态势感知方面。
ML 提供了使常规功能自动化的机会，从而使员工能够承担其他更大的增值任务。
机器学习基础科学的进步将不断需要由国家气象水文部门 (National Meteorological and Hydrological Services, NMHS) 和私营部门转化为新产品和新服务。&lt;/p&gt;</description></item><item><title>2021年第一季度工作总结</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-04-2021-q1-summray/</link><pubDate>Tue, 06 Apr 2021 10:32:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-04-2021-q1-summray/</guid><description>&lt;p&gt;又是一年清明时。&lt;/p&gt;
&lt;p&gt;去年清明正值全国哀悼日，悼念抗击新冠肺炎疫情斗争牺牲烈士和逝世同胞。
我也写了一篇短文《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-04-may-all-the-deceased-rest-in-peace/"&gt;愿逝者安息&lt;/a&gt;》，里面提到要时刻审视自己，注意国家大事对自己的影响。
一年之后再看，我可能需要再加上一句：要注意单位改革对自己的影响。&lt;/p&gt;
&lt;p&gt;上个季度总结中计划今年第一季度有四项工作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;撰写技术报告&lt;/li&gt;
&lt;li&gt;研究 ESMValTool 如何与分布式调度工具集成&lt;/li&gt;
&lt;li&gt;完成 NWPC 消息平台所有考核指标&lt;/li&gt;
&lt;li&gt;研究基于 Dask 的分布式数据处理技术&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际上我只完成了前两项，后两项工作则完全没有开展。&lt;/p&gt;
&lt;h2 id="技术报告"&gt;技术报告&lt;/h2&gt;
&lt;p&gt;1 月完成一篇技术报告《基于消息通讯的数值预报业务系统运行监视和分析技术研发》，已提交单位审核，目前在等待评审结果。&lt;/p&gt;
&lt;p&gt;第一季度有两篇文章与该技术报告相关：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2021/01/2021-01-05-elasticsearch-scroll-api-for-large-query/"&gt;ElasticSearch使用Scroll检索大规模数据&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2021/01/2021-01-05-nwpc-message-task-situation-dfs-for-ecflow-client-message/"&gt;NWPC消息平台：运行状态分析算法&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;另外，还对模式运行时长进行了一项比较粗糙的分析&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2021/02/2021-02-06-is-running-time-of-nwp-models-the-same-at-different-cycle/"&gt;数值预报模式不同时次运行时长是否相同？&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;这篇发布到公众号的文章被转到单位群中，导致我后续不敢再胡乱在公众号上发布新的文章，也间接影响了自己持续学习的动力。
不过现在我逐渐觉得自己不应该瞻前顾后，对于技术类文章还是想发就发，不要考虑质量，毕竟这不是在发表论文。&lt;/p&gt;
&lt;h2 id="诊断工具"&gt;诊断工具&lt;/h2&gt;
&lt;p&gt;从 1 月中旬到 3 月底将近两个半月的时间，我都在研究 ESMValTool 工具，基本摸清该工具数据处理部分的流程，并将该工具与之前开发的分布式调度工具 &lt;a href="https://github.com/perillaroc/ploto"&gt;ploto&lt;/a&gt; 整合，重新实现 &lt;a href="https://github.com/perillaroc/ploto-esmvaltool"&gt;ploto-esmvaltool&lt;/a&gt; 项目。&lt;/p&gt;
&lt;p&gt;分析 ESMValTool 工具的最大难点在于数据的缺失。为了跑通各个诊断方法，必须要下载需要的全部数据，包括 CMIP6 数据和各类观测资料数据，花费大量时间。
目前仅测试跑通该工具三分之一的方法，整合 ESMValCore 提供的大部分数据处理方法。
不过，我还没有从在上一季度总结中提到的工作流角度思考集成问题，现有方案拆解的步骤只能串行执行，远不如 ESMValTool 工具提供的多进程执行效率。
想要做一些高附加值的工作，就需要从实现轻量级工作流方面入手，将各个步骤并发执行。&lt;/p&gt;
&lt;p&gt;我也一直在质疑花费大量时间研究 ESMValTool 工具对我的工作会有什么帮助，毕竟单位目前不跑气候模式，我也不做诊断方面的开发工作。
不找到与当前工作的结合点，之前花费的时间精力很可能就打了水漂。
对于 ESMValTool 工具，我认为可以借鉴它优秀的 API 接口设计理念，可以参考它的方法函数，实现自己的数据处理函数工具集。
在这方面我才刚刚起步。&lt;/p&gt;
&lt;h2 id="数据工具"&gt;数据工具&lt;/h2&gt;
&lt;p&gt;作为参考 ESMValTool 数据 API 设计的第一步，我研究如何使用不同的工具库对 GRIB2 数据的二维格点场进行插值。
详情参见如下文章：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2021/03/2021-03-16-grib-notebook-interpolate-using-scipy/"&gt;GRIB笔记：使用scipy实现二维要素场插值&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2021/03/2021-03-20-grib-notebook-interpolate-using-xarray/"&gt;GRIB笔记：使用xarray实现二维要素场插值&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2021/03/2021-03-27-grib-notebook-interpolate-using-pyinterp/"&gt;GRIB笔记：使用pyinterp实现二维要素场插值&lt;/a&gt;》&lt;/p&gt;</description></item><item><title>论文阅读：气候模式代码可访问性调查</title><link>https://blog.perillaroc.wang/post/2021/04/2021-04-02-paper-anel-2021-status-on-accessibility-to-climate-models-code/</link><pubDate>Fri, 02 Apr 2021 22:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/04/2021-04-02-paper-anel-2021-status-on-accessibility-to-climate-models-code/</guid><description>&lt;p&gt;Current status on the need for improved accessibility to climate models code&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Añel, J. A., García-Rodríguez, M., and Rodeiro, J.: Current status on the need for improved accessibility to climate models code, Geosci. Model Dev., 14, 923–934, &lt;a href="https://doi.org/10.5194/gmd-14-923-2021"&gt;https://doi.org/10.5194/gmd-14-923-2021&lt;/a&gt;, 2021.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是一篇非常有趣的论文，作者调查是否可以获取参与 CMIP5 项目各个气候模式的源代码，并对拿到的源码材料进行简单的分析，发表在《Geoscientific Model Development》期刊上。&lt;/p&gt;
&lt;p&gt;没想到真有研究人员会逐个验证总计 26 个 CMIP5 项目模式的源码是否可以公开。
如果将这项工作扩展到 CMIP6 项目中，可以想象任务量会大大增加。&lt;/p&gt;
&lt;p&gt;下面&lt;strong&gt;正文&lt;/strong&gt;章节简要介绍论文的内容，翻译底稿来自谷歌翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;CSR：computational scientific repreducibility&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由美国国家学院定义，意思是“使用相同的输入数据，计算方法和分析条件获得一致的结果”。&lt;/p&gt;
&lt;p&gt;现在，越来越多的期刊都采用计算机代码政策 (computer-code policies)。
研究人员也提出一些建议，以确保结果具有更高的可重复性，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;维护软件的适当文档&lt;/li&gt;
&lt;li&gt;将代码拆分为函数&lt;/li&gt;
&lt;li&gt;将代码提交给发布 DOI 的存储库&lt;/li&gt;
&lt;li&gt;鼓励外部协作者参与并简化协作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作者认为公开代码可以防止模式迭代更新过程中的知识丢失，并指出模式代码普遍没有达到理想的编程实践层次，复现结果也需要共享代码。&lt;/p&gt;
&lt;h3 id="调查方法"&gt;调查方法&lt;/h3&gt;
&lt;p&gt;作者通过 CMIP5 官方网站、电子邮箱、网上搜索等多种方式获取模式源码信息，向模式研发人员多次发送邮件，并询问不公开源码原因的选项（不过没有中心回复具体的原因）。&lt;/p&gt;</description></item><item><title>R语言实战：时间序列</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-30-r-in-action-chap15-time-series/</link><pubDate>Tue, 30 Mar 2021 22:29:48 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-30-r-in-action-chap15-time-series/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;横截面数据 (cross-sectional)：给定一个时间点测量变量的值&lt;/p&gt;
&lt;p&gt;纵向数据 (longitudinal)：随着时间的变化反复测量变量值&lt;/p&gt;
&lt;p&gt;时间序列：给定一段时间内有规律地记录的观测值&lt;/p&gt;
&lt;h2 id="在-r-中生成时序对象"&gt;在 R 中生成时序对象&lt;/h2&gt;
&lt;p&gt;时间序列对象 (time-series object)：R 中一种包括观测值、起始时间、终止时间以及周期 (如月、季度或年) 的结构&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ts()&lt;/code&gt; 生成时间序列对象&lt;/p&gt;
&lt;p&gt;&lt;code&gt;frequency&lt;/code&gt; 参数指定每个单位时间所包含的观测值数量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;frequency=1&lt;/code&gt;：年数据&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frequency=4&lt;/code&gt;：季度数据&lt;/li&gt;
&lt;li&gt;&lt;code&gt;frequency=12&lt;/code&gt;：月数据&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sales &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;33&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;41&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;34&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;29&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;21&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;54&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;26&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tsales &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ts&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sales,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2003&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frequency&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tsales
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2003 18 33 41 7 34 35 24 25 24 21 25 20
2004 22 31 40 29 25 21 22 54 32 25 26 35
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(tsales)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/r/ria/chap15/plot-tsales.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>读书笔记：下沉年代</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-28-book-the-unwinding/</link><pubDate>Sun, 28 Mar 2021 21:00:11 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-28-book-the-unwinding/</guid><description>&lt;p&gt;原作名：The Unwinding: An Inner History of the New America&lt;/p&gt;
&lt;p&gt;通过四个主线人物和一系列支线人物的故事，展现美国从1978年到2012年这30年间的社会变迁。
我对美国完全不了解，但也能从这些故事中略微理解为什么2020年美国总统大选会出现这么极端的对立冲突，为什么让美国再次伟大，美国优先和去全球化在美国会有这么多人支持。&lt;/p&gt;
&lt;p&gt;书中沃尔玛的例子就能很好地说明资本对社会的影响。
低价的沃尔玛强烈冲击本地商业，大量就业机会随着小商店的倒闭而消失，失业的人将不得不为这些大型企业打工。
可以对比前一段时间国内互联网公司进军社区团购领域，及时被监管部门叫停，保住了菜市场。&lt;/p&gt;
&lt;p&gt;为了追求低价，资本将提供上万工作岗位的大型工厂迁往沿海城市，迁往人力成本更低的其他国家，传统工业城市逐渐衰落，形成了所谓的锈带。
从六七十年代任何高中毕业生都能在当地工厂中找到工作，发展到次贷危机中跑遍整个城市也找不到一份工作。
本以为会一直工作到退休领取养老金，却没想到有一天竟然会失业。
在谷歌地图街景中查看书中介绍的扬斯敦市中心，龟裂的道路完全看不出这里在七十年代曾经是一个重要的钢铁工业中心。
正如书中所说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“一个多世纪以来，在当地社区担当制度核心支柱的公司仿佛会永远存在，如今却纷纷消失在眨眼之间”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同样，在中国也没有什么工作是铁饭碗，1998 年的国企改革已充分说明这一点。&lt;/p&gt;
&lt;p&gt;而上述这一切却影响不到华盛顿和华尔街等“体制”内人士。正如书中所说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“体制通过提升人们的品质来展示它们在健康运转，哪怕这些人偏离了道路，他们也能在自我纠正中找到最重要的力量。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“当某些行为不再需要付出代价，当连那些阻止人们炫耀他们赚钱方式的准则都开始受到侵蚀并逐渐消失，文化改变了。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当失业家庭等待福利补助金，“靠刷食品券购买的加工毒药为食”，无房家庭晚上睡在车中的时候，他们告诉这些家庭“任何人只要对有机草莓心怀足够的热情，就肯定买得起它们”，他们让他们“无法找到任何借口，因为生命中不存在随机的痛苦”，仿佛“每个人都得成为计算机程序员和金融工程师”。
全书也就只有从印度来的新美国居民“仍能看到一个光明的未来，就算她自己无法抵达，她的孩子也可以”，即使她在次贷危机中竭尽全力才与银行达成和解，保住了自己的汽车旅馆。&lt;/p&gt;
&lt;p&gt;书中围绕 2008 年次贷危机，通过多个角度描述了代表不同利益的群体和个人。
比如政客围绕政府是否放宽对金融的监管而做的各种博弈，报纸记者调查房地产信贷而做出的努力，自媒体人如何改变叙事而获得最大利益，本地居民对城市是否修建轻轨的争论，生物燃油的创业者在油价下行阶段的失落与重振，占领华尔街运动的突然兴起与黯然落幕，信仰自由意志的硅谷大亨期望延长寿命而投资生物科技公司。
最终的结果就是银行家和金融业依然繁荣，没有谁为次贷危机负责。看到书中次贷危机中破产家庭的挣扎，我觉得还是尽量不要贷款，类似买手机之类的消费还是不要考虑分期付款了。&lt;/p&gt;
&lt;p&gt;我从书中看到，每个人都在维护自己的利益，这也许就是美国精神。
唯一可惜的一点就是书中的故事到2012年就结束了，没有特朗普时期的故事，否则会更加精彩。&lt;/p&gt;
&lt;p&gt;本书是一部非常优秀的译著，读起来非常流畅。不知道有没有描述中国当代历史的书籍，后面可以找来看看。&lt;/p&gt;
&lt;p&gt;为了秉承乐观的态度，最后用书中人物的话做结尾：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“你必须相信某些事情。… 我相信人有可能自我改善，我们作为一个文明社会能变得更好。”&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>GRIB笔记：使用pyinterp实现二维要素场插值</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-27-grib-notebook-interpolate-using-pyinterp/</link><pubDate>Sun, 28 Mar 2021 19:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-27-grib-notebook-interpolate-using-pyinterp/</guid><description>&lt;p&gt;介绍如何使用 pyinterp 实现二维矩阵插值&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;加载 Python 科学常用库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; cartopy.crs &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ccrs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 nwpc-data 库加载 GRIB2 要素场&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_field_from_file,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载 pyinterp 库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pyinterp
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pyinterp.fill
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pyinterp.backends.xarray
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2021031100&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;24h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;PosixPath(&amp;#39;/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2021031100/ORIG/gmf.gra.2021031100024.grb2&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2t&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;273.15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data/grib2/interpolate/pyinterp/2t.png" alt=""&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m&lt;span style="color:#f92672"&gt;.&lt;/span&gt;values&lt;span style="color:#f92672"&gt;.&lt;/span&gt;shape
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;(720, 1440)
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(field):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;figure(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;axes(projection&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccrs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PlateCarree())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; field&lt;span style="color:#f92672"&gt;.&lt;/span&gt;plot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ax
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;.&lt;/span&gt;coastlines()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;show()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot(t2m)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data/grib2/interpolate/pyinterp/t2m-plot.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>论文阅读：数字时代开放的天气和气候科学</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-26-paper-martine-2020-open-weather-and-climate-science-in-the-digital-era/</link><pubDate>Sat, 27 Mar 2021 13:38:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-26-paper-martine-2020-open-weather-and-climate-science-in-the-digital-era/</guid><description>&lt;blockquote&gt;
&lt;p&gt;de Vos M G, Hazeleger W, Bari D, et al. Open weather and climate science in the digital era[J]. Geoscience Communication, 2020, 3(2): 191-201.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gc.copernicus.org/articles/3/191/2020/gc-3-191-2020.html"&gt;https://gc.copernicus.org/articles/3/191/2020/gc-3-191-2020.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;虽然我是一个软件开源的坚定拥护者，已将自己的绝大部分工作都发布为开源项目，也在年终总结等多个场合下宣传大家加入到开源的大家庭中，但我确实没有想到在气象领域竟然能看到鼓吹开放的论文。&lt;/p&gt;
&lt;p&gt;论文对 2018 年 IEEE 专题讨论会 Weather and Climate Science in the Digital Era 中的报告进行分析，于 2019 年 10 月投稿，并在 2020 年 8 月发表。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;气象和气候科学界已经意识到对开放科学 (open science) 的需求，尽管这些领域在应用数字技术方面已经非常成熟，但在实施开放式科学方法方面却不那么先进。&lt;/p&gt;
&lt;p&gt;讨论会中大概 80% 的研究都显示了开放数据和软件的附加价值，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同来源的开放数据集&lt;/li&gt;
&lt;li&gt;可公开提供给研究社区的工具和方法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但这些不足以实现开放的天气和气候科学。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;FAIR 准则：Findable, Accessible, Interoperable, Reusable&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;将 FAIR 准则应用到数据集上具有挑战性。
当然更多的挑战是非技术性的，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;技术人员与领域科学家的合作&lt;/li&gt;
&lt;li&gt;共享数据的法律问题&lt;/li&gt;
&lt;li&gt;通过政策吸引利益相关者参与开放&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作者认为发展开放的天气和气候科学需要做出改变，但带来的好处是巨大的。&lt;/p&gt;</description></item><item><title>WeatherBench：创建线性回归模型</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-21-weatherbench-linear-regression/</link><pubDate>Sun, 21 Mar 2021 18:41:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-21-weatherbench-linear-regression/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自 weatherbench 项目源码：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/pangeo-data/WeatherBench/blob/master/notebooks/2-linear-regression-baseline.ipynb"&gt;https://github.com/pangeo-data/WeatherBench/blob/master/notebooks/2-linear-regression-baseline.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这个笔记本中，我们将创建线性回归基线模型&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; seaborn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pickle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# from src.score import *&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sklearn.linear_model &lt;span style="color:#f92672"&gt;import&lt;/span&gt; LinearRegression
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sklearn.metrics &lt;span style="color:#f92672"&gt;import&lt;/span&gt; mean_squared_error
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; tqdm &lt;span style="color:#f92672"&gt;import&lt;/span&gt; tqdm_notebook &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; tqdm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_style(&lt;span style="color:#e6db74"&gt;&amp;#39;darkgrid&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_context(&lt;span style="color:#e6db74"&gt;&amp;#39;notebook&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_pickle&lt;/span&gt;(obj, fn):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(fn, &lt;span style="color:#e6db74"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pickle&lt;span style="color:#f92672"&gt;.&lt;/span&gt;dump(obj, f)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read_pickle&lt;/span&gt;(fn):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(fn, &lt;span style="color:#e6db74"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; pickle&lt;span style="color:#f92672"&gt;.&lt;/span&gt;load(f)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="为训练加载和准备数据"&gt;为训练加载和准备数据&lt;/h2&gt;
&lt;p&gt;首先，我们需要加载和准备数据。
这样我们可以将其馈入到我们的线性回归模型中&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/g11/wangdp/data/weather-bench/5.625deg&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;baseline_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/g11/wangdp/data/weather-bench/baselines-wangdp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载相关变量的整个数据集，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;500hPa 位势高度&lt;/li&gt;
&lt;li&gt;850hPa 温度&lt;/li&gt;
&lt;li&gt;6 小时累计降水&lt;/li&gt;
&lt;li&gt;2 米温度&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z500 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/geopotential_500/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;z&lt;span style="color:#f92672"&gt;.&lt;/span&gt;drop(&lt;span style="color:#e6db74"&gt;&amp;#39;level&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t850 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/temperature_850/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;t&lt;span style="color:#f92672"&gt;.&lt;/span&gt;drop(&lt;span style="color:#e6db74"&gt;&amp;#39;level&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/total_precipitation/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rolling(time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;tp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/2m_temperature/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;t2m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;合并为一个数据集。&lt;/p&gt;</description></item><item><title>GRIB笔记：使用xarray实现二维要素场插值</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-20-grib-notebook-interpolate-using-xarray/</link><pubDate>Sun, 21 Mar 2021 10:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-20-grib-notebook-interpolate-using-xarray/</guid><description>&lt;p&gt;介绍如何使用 xarray 实现二维矩阵插值。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;加载 Python 常用科学库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; cartopy.crs &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ccrs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 库查找数据文件，并加载要素场&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_field_from_file,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2021031100&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;24h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;PosixPath(&amp;#39;/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2021031100/ORIG/gmf.gra.2021031100024.grb2&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用 &lt;code&gt;load_field_from_file()&lt;/code&gt; 加载要素场，返回 &lt;code&gt;xarray.DataArray&lt;/code&gt; 对象&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2t&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;273.15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data/grib2/interpolate/xarray/2t.png" alt=""&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m&lt;span style="color:#f92672"&gt;.&lt;/span&gt;values&lt;span style="color:#f92672"&gt;.&lt;/span&gt;shape
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;(720, 1440)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用 xarray 内置的 &lt;code&gt;plot()&lt;/code&gt; 函数进行绘图&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(field):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;figure(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;axes(projection&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccrs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PlateCarree())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; field&lt;span style="color:#f92672"&gt;.&lt;/span&gt;plot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ax
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;.&lt;/span&gt;coastlines()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;show()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot(t2m)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/data/grib2/interpolate/xarray/t2m-plot.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>WeatherBench：创建气候态和持续性预报</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-16-weatherbench-climatology-persistence/</link><pubDate>Tue, 16 Mar 2021 22:04:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-16-weatherbench-climatology-persistence/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文来自 weatherbench 项目源码：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/pangeo-data/WeatherBench/blob/master/notebooks/1-climatology-persistence.ipynb"&gt;https://github.com/pangeo-data/WeatherBench/blob/master/notebooks/1-climatology-persistence.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在本文中，我们将创建最基本的基准：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;气候态，climatology&lt;/li&gt;
&lt;li&gt;持续性预报，persistence forecast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们将在 500hPa 位势高度，850hPa 温度，降水和 2m 温度下进行此操作&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; seaborn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_style(&lt;span style="color:#e6db74"&gt;&amp;#39;darkgrid&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_context(&lt;span style="color:#e6db74"&gt;&amp;#39;notebook&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="加载数据"&gt;加载数据&lt;/h2&gt;
&lt;p&gt;首选，我们需要指定目录并加载数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;5.625&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/g11/wangdp/data/weather-bench/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;res&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;deg&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;baseline_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/g11/wangdp/data/weather-bench/baselines-wangdp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;列出数据目录下的所有子目录&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;10m_u_component_of_wind geopotential_500 toa_incident_solar_radiation
10m_v_component_of_wind potential_vorticity total_cloud_cover
2m_temperature		 relative_humidity total_precipitation
all_5.625deg.zip	 specific_humidity u_component_of_wind
constants		 temperature	 v_component_of_wind
geopotential		 temperature_850 vorticity
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;加载全部 2m 温度数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/2m_temperature/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/ml/weatherbench/climatology/all-2mt.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;加载相关变量&lt;/p&gt;
&lt;p&gt;注意：需要通过计算得到 6 小时累计降水&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z500 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/geopotential_500/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;z
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t850 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/temperature_850/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;t&lt;span style="color:#f92672"&gt;.&lt;/span&gt;drop(&lt;span style="color:#e6db74"&gt;&amp;#39;level&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/total_precipitation/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rolling(time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;tp&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t2m &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_mfdataset(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;data_dir&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/2m_temperature/*.nc&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; combine&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;by_coords&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;t2m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构建完整数据集&lt;/p&gt;</description></item><item><title>GRIB笔记：使用scipy实现二维要素场插值</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-16-grib-notebook-interpolate-using-scipy/</link><pubDate>Tue, 16 Mar 2021 21:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-16-grib-notebook-interpolate-using-scipy/</guid><description>&lt;p&gt;介绍 &lt;code&gt;scipy.interpolate&lt;/code&gt; 包中几种可用于二维矩阵插值的函数&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.scipy.org/doc/scipy/reference/interpolate.html"&gt;https://docs.scipy.org/doc/scipy/reference/interpolate.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;本文仅简要介绍函数用法，而不比较各种插值类型。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;加载 Python 常用科学库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; cartopy.crs &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ccrs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 eccodes 包解码 GRIB2 文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; eccodes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 库查找数据文件，并加载要素场&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_message_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;使用 GRAPES GFS 全球预报模式系统生成的原始分辨率 GRIB2 产品，分辨率为 0.25 度，网格大小 1440 * 720&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2021031100&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;24h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;PosixPath(&amp;#39;/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2021031100/ORIG/gmf.gra.2021031100024.grb2&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用 &lt;code&gt;load_message_from_file()&lt;/code&gt; 函数加载 2 米温度场，返回用于 eccodes 包的 GRIB handler 对象&lt;/p&gt;</description></item><item><title>R语言实战：主成分分析和因子分析</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-12-r-in-action-chap14-pca-and-eda/</link><pubDate>Sat, 13 Mar 2021 00:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-12-r-in-action-chap14-pca-and-eda/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主成分分析 (PCA)：一种数据降维技巧，将大量相关变量转化为一组很少的不相关变量，这些无关变量被称为主成分。&lt;/p&gt;
&lt;p&gt;探索性因子分析 (EDA)：用来发现一组变量的潜在结构的一系列方法，通过寻找一组更小的、潜在的或隐藏的结构来解释已观测到的、显式的变量间的关系。&lt;/p&gt;
&lt;h2 id="r-中的主成分和因子分析"&gt;R 中的主成分和因子分析&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(psych)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;常见步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据预处理。输入原始数据矩阵或者相关系数矩阵给 &lt;code&gt;principal()&lt;/code&gt; 和 &lt;code&gt;fa()&lt;/code&gt; 函数&lt;/li&gt;
&lt;li&gt;选择因子模型&lt;/li&gt;
&lt;li&gt;判断要选择的主成分/因子数目&lt;/li&gt;
&lt;li&gt;选择主成分/因子&lt;/li&gt;
&lt;li&gt;旋转主成分/因子&lt;/li&gt;
&lt;li&gt;解释结果&lt;/li&gt;
&lt;li&gt;计算主成分或因子得分&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="主成分分析"&gt;主成分分析&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(USJudgeRatings)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; CONT INTG DMNR DILG CFMG DECI PREP FAMI ORAL WRIT PHYS RTEN
AARONSON,L.H. 5.7 7.9 7.7 7.3 7.1 7.4 7.1 7.1 7.1 7.0 8.3 7.8
ALEXANDER,J.M. 6.8 8.9 8.8 8.5 7.8 8.1 8.0 8.0 7.8 7.9 8.5 8.7
ARMENTANO,A.J. 7.2 8.1 7.8 7.8 7.5 7.6 7.5 7.5 7.3 7.4 7.9 7.8
BERDON,R.I. 6.8 8.8 8.5 8.8 8.3 8.5 8.7 8.7 8.4 8.5 8.8 8.7
BRACKEN,J.J. 7.3 6.4 4.3 6.5 6.0 6.2 5.7 5.7 5.1 5.3 5.5 4.8
BURNS,E.B. 6.2 8.8 8.7 8.5 7.9 8.0 8.1 8.0 8.0 8.0 8.6 8.6
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="判断主成分的个数"&gt;判断主成分的个数&lt;/h3&gt;
&lt;p&gt;Kaiser-Harris 准则&lt;/p&gt;</description></item><item><title>WeatherBench：查看数据集</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-10-weatherbench-check-data/</link><pubDate>Wed, 10 Mar 2021 23:34:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-10-weatherbench-check-data/</guid><description>&lt;p&gt;介绍 WeatherBench 中由 ERA5 再分析资料制作的 5.625 度数据 (网格：32x64)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pathlib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="文件说明"&gt;文件说明&lt;/h2&gt;
&lt;p&gt;数据目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;base_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/g11/wangdp/data/weather-bench/5.625deg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个要素保存到单独的目录中，一共 17 个目录，16 个要素目录 + 1 个常量目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f &lt;span style="color:#f92672"&gt;in&lt;/span&gt; Path(base_path)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;iterdir() &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;is_file()]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[&amp;#39;10m_u_component_of_wind&amp;#39;,
 &amp;#39;10m_v_component_of_wind&amp;#39;,
 &amp;#39;2m_temperature&amp;#39;,
 &amp;#39;constants&amp;#39;,
 &amp;#39;geopotential&amp;#39;,
 &amp;#39;geopotential_500&amp;#39;,
 &amp;#39;potential_vorticity&amp;#39;,
 &amp;#39;relative_humidity&amp;#39;,
 &amp;#39;specific_humidity&amp;#39;,
 &amp;#39;temperature&amp;#39;,
 &amp;#39;temperature_850&amp;#39;,
 &amp;#39;toa_incident_solar_radiation&amp;#39;,
 &amp;#39;total_cloud_cover&amp;#39;,
 &amp;#39;total_precipitation&amp;#39;,
 &amp;#39;u_component_of_wind&amp;#39;,
 &amp;#39;v_component_of_wind&amp;#39;,
 &amp;#39;vorticity&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;单个要素目录中，每个文件保存 1 年数据，一共 40 个文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f &lt;span style="color:#f92672"&gt;in&lt;/span&gt; Path(base_path, &lt;span style="color:#e6db74"&gt;&amp;#34;temperature&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;iterdir() &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;is_file()]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[&amp;#39;temperature_1979_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1980_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1981_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1982_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1983_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1984_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1985_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1986_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1987_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1988_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1989_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1990_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1991_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1992_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1993_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1994_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1995_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1996_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1997_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1998_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_1999_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2000_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2001_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2002_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2003_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2004_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2005_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2006_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2007_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2008_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2009_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2010_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2011_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2012_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2013_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2014_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2015_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2016_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2017_5.625deg.nc&amp;#39;,
 &amp;#39;temperature_2018_5.625deg.nc&amp;#39;]
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="单层要素2m-温度"&gt;单层要素：2m 温度&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;variable_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2m_temperature&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;short_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;t2m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;year &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2013&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Path(base_path, variable_name, &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;variable_name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;year&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;_5.625deg.nc&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;PosixPath(&amp;#39;/g11/wangdp/data/weather-bench/5.625deg/2m_temperature/2m_temperature_2013_5.625deg.nc&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="加载单个文件"&gt;加载单个文件&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;open_dataset(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/ml/weatherbench/check-data/ds-t2m.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>GRIB笔记：使用cfgrib加载GRIB文件</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-16-grib-notebook-read-grib-using-cfgrib/</link><pubDate>Wed, 10 Mar 2021 20:49:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-16-grib-notebook-read-grib-using-cfgrib/</guid><description>&lt;p&gt;&lt;a href="https://github.com/ecmwf/cfgrib"&gt;cfgrib&lt;/a&gt; 是 ECMWF 开发的 GRIB Python 接口，支持 &lt;a href="https://www.unidata.ucar.edu/software/thredds/current/netcdf-java/CDM/"&gt;Unidata&amp;rsquo;s Common Data Model v4&lt;/a&gt;，符合 &lt;a href="http://cfconventions.org/"&gt;CF Conventions&lt;/a&gt;。
高层 API 接口为 xarray 提供 GRIB 解码引擎。
底层访问和解码由 ECMWF 的 &lt;a href="https://software.ecmwf.int/wiki/display/ECC/"&gt;ecCodes&lt;/a&gt; 库实现。&lt;/p&gt;
&lt;h2 id="功能"&gt;功能&lt;/h2&gt;
&lt;p&gt;cfgrib 正在开发中，处于 Beta 版本的功能有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持 xarray 使用 &lt;code&gt;engine=&amp;quot;cfgrib&amp;quot;&lt;/code&gt; 读取 GRIB文 件。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;cfgrib.open_datasets&lt;/code&gt; 能读取大部分 GRIB 1 和 2 文件，包括包含不同层次类型的文件&lt;/li&gt;
&lt;li&gt;支持所有现代 Python 版本，包括 3.9，3.8，3.7，3.6 和 PyPy3&lt;/li&gt;
&lt;li&gt;支持 Python 2 的 0.9.6.x 系列将继续维护并接收重要的错误修正，&lt;/li&gt;
&lt;li&gt;支持 Linux、MacOS 和 Windows，唯一的依赖是 ecCodes 的 C 库&lt;/li&gt;
&lt;li&gt;所有支持的平台都可以使用 conda-forge 包安装&lt;/li&gt;
&lt;li&gt;延迟和高效读取数据，节省内存占用和磁盘访问&lt;/li&gt;
&lt;li&gt;允许使用 &lt;strong&gt;dask&lt;/strong&gt; 进行大于内存的分布式处理&lt;/li&gt;
&lt;li&gt;支持将坐标转换为不同的数据模型和命名约定&lt;/li&gt;
&lt;li&gt;支持将 GRIB 文件的索引写入磁盘，以在打开时保存全文件扫描&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;处于 Alpha 的功能有：&lt;/p&gt;</description></item><item><title>Cloud-Ws 2021：格点数据的数据服务Gridefix</title><link>https://blog.perillaroc.wang/post/2021/03/2021-03-07-cloud-ws-2021-gridefix/</link><pubDate>Tue, 09 Mar 2021 23:48:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/03/2021-03-07-cloud-ws-2021-gridefix/</guid><description>&lt;p&gt;本文&lt;strong&gt;正文&lt;/strong&gt;部分来自 ECMWF 于 2021 年 2 月召开的 &lt;strong&gt;Virtual workshop: Weather and climate in the cloud&lt;/strong&gt; (Cloud-WS 2021) 中的如下演讲：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Data service for gridded data&lt;/p&gt;
&lt;p&gt;Code name: Gridefix&lt;/p&gt;
&lt;p&gt;by Philipp Falke, Matthieu Bernard, Gabriela Aznar&lt;/p&gt;
&lt;p&gt;at Cloud-WS 2021&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;基于 zarr 和 xarray 面向强天气数据的数据服务&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/cloud-ws-2021/gridefix/slide-p01.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图片来自幻灯片&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;h4 id="背景"&gt;背景&lt;/h4&gt;
&lt;p&gt;当作者三年前入职时，天气数据的存储方式仅有文件。。。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/cloud-ws-2021/gridefix/files.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图片来自幻灯片&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;格点数据库的最初原型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;文件编目&lt;/p&gt;
&lt;p&gt;支持 NWP 模式和卫星数据&lt;/p&gt;
&lt;p&gt;基于 OPeNDAP API 对文件概念进行抽象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总是需要 2 个 API 调用：catalogue 和 dataset&lt;/li&gt;
&lt;li&gt;数组的冗余切片&lt;/li&gt;
&lt;li&gt;大量的即时处理&lt;/li&gt;
&lt;li&gt;难以使用随机方式 (random manner) 访问数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="需求"&gt;需求&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/cloud-ws-2021/gridefix/slide-p04.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>Cloud-Ws 2021：事件通知工具Aviso</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-28-cloud-ws-2021-aviso/</link><pubDate>Mon, 01 Mar 2021 23:36:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-28-cloud-ws-2021-aviso/</guid><description>&lt;p&gt;本文&lt;strong&gt;正文&lt;/strong&gt;部分来自 ECMWF 于 2021 年 2 月召开的 &lt;strong&gt;Virtual workshop: Weather and climate in the cloud&lt;/strong&gt; (Cloud-WS 2021) 中的如下演讲：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enabling machine learning for weather and climate data in the cloud&lt;/p&gt;
&lt;p&gt;Enabling notifications for meteorological workflows across HPC and Cloud data centres&lt;/p&gt;
&lt;p&gt;by C. Iacopino, J. Hawkes, T. Quintino, B. Raoult&lt;/p&gt;
&lt;p&gt;at Cloud-WS 2021&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aviso：为 HPC 和 Cloud 数据中心的气象工作流启用通知&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;h4 id="背景"&gt;背景&lt;/h4&gt;
&lt;p&gt;Cloud Data-as-a-Service&lt;/p&gt;
&lt;p&gt;ECMWF 每天生成大量数据，原始数据输出和分发产品的大小在持续增长：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5km 集合预报，将在 1 小时内生成 1 PB 数据&lt;/li&gt;
&lt;li&gt;将数据从中心转移出去变得令人望而却步&lt;/li&gt;
&lt;li&gt;云数据模型：将计算向数据靠拢&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/cloud-ws-2021/aviso/cloud-daas.jpg" alt=""&gt;
&lt;strong&gt;图片来自幻灯片&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Cloud-WS 2021：数据工具库CliMetLab</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-22-cloud-ws-2021-climetlab/</link><pubDate>Fri, 26 Feb 2021 22:25:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-22-cloud-ws-2021-climetlab/</guid><description>&lt;p&gt;本文&lt;strong&gt;正文&lt;/strong&gt;部分来自 ECMWF 于 2021 年 2 月召开的 &lt;strong&gt;Virtual workshop: Weather and climate in the cloud&lt;/strong&gt; (Cloud-WS 2021) 中的如下演讲：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enabling machine learning for weather and climate data in the cloud&lt;/p&gt;
&lt;p&gt;A Python package to support AI/ML activities in climate and meteorology&lt;/p&gt;
&lt;p&gt;by Baudouin Raoult&lt;/p&gt;
&lt;p&gt;at Cloud-WS 2021&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;CliMetLib：一个用于支持气候和气象学中的 AI/ML 研究的 Python 包&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;注：笔者对演讲幻灯片中部分内容有修改和调整&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="概述"&gt;概述&lt;/h3&gt;
&lt;h4 id="jupyter-notebook"&gt;Jupyter Notebook&lt;/h4&gt;
&lt;p&gt;Jupyter Notebooks 中通常可以看到大量与 AI/ML 方法无关的代码：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取数据
&lt;ul&gt;
&lt;li&gt;网络访问：wget，curl&lt;/li&gt;
&lt;li&gt;解压：unzip，untar&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解码数据
&lt;ul&gt;
&lt;li&gt;GRIB&lt;/li&gt;
&lt;li&gt;NetCDF&lt;/li&gt;
&lt;li&gt;CSV&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;修改绘图属性，使图像更好看&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而与 AI/ML 相关的代码通常很少。&lt;/p&gt;</description></item><item><title>ISLR实验：PCR和PLS回归</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-25-islr-lab-chap06-dimension-reduction/</link><pubDate>Thu, 25 Feb 2021 22:20:20 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-25-islr-lab-chap06-dimension-reduction/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《6.7 实验3：PCR 和 PLS 回归》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍两种降维 (dimension reduction) 方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主成分回归 (principal components regression, PCR)&lt;/li&gt;
&lt;li&gt;偏最小二乘 (partial least squares, PLS)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(pls)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;棒球数据集，使用若干与棒球运动员上一年比赛成绩相关的变量来预测该运动员的薪水 (Salary)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; AtBat Hits HmRun Runs RBI Walks Years CAtBat CHits
-Andy Allanson 293 66 1 30 29 14 1 293 66
-Alan Ashby 315 81 7 24 38 39 14 3449 835
-Alvin Davis 479 130 18 66 72 76 3 1624 457
-Andre Dawson 496 141 20 65 78 37 11 5628 1575
-Andres Galarraga 321 87 10 39 42 30 2 396 101
-Alfredo Griffin 594 169 4 74 51 35 11 4408 1133
 CHmRun CRuns CRBI CWalks League Division PutOuts Assists
-Andy Allanson 1 30 29 14 A E 446 33
-Alan Ashby 69 321 414 375 N W 632 43
-Alvin Davis 63 224 266 263 A W 880 82
-Andre Dawson 225 828 838 354 N E 200 11
-Andres Galarraga 12 48 46 33 N E 805 40
-Alfredo Griffin 19 501 336 194 A W 282 421
 Errors Salary NewLeague
-Andy Allanson 20 NA A
-Alan Ashby 10 475.0 N
-Alvin Davis 14 480.0 A
-Andre Dawson 3 500.0 N
-Andres Galarraga 4 91.5 N
-Alfredo Griffin 25 750.0 A
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dim&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 322 20
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [1] &amp;#34;AtBat&amp;#34; &amp;#34;Hits&amp;#34; &amp;#34;HmRun&amp;#34; &amp;#34;Runs&amp;#34; &amp;#34;RBI&amp;#34; 
 [6] &amp;#34;Walks&amp;#34; &amp;#34;Years&amp;#34; &amp;#34;CAtBat&amp;#34; &amp;#34;CHits&amp;#34; &amp;#34;CHmRun&amp;#34; 
[11] &amp;#34;CRuns&amp;#34; &amp;#34;CRBI&amp;#34; &amp;#34;CWalks&amp;#34; &amp;#34;League&amp;#34; &amp;#34;Division&amp;#34; 
[16] &amp;#34;PutOuts&amp;#34; &amp;#34;Assists&amp;#34; &amp;#34;Errors&amp;#34; &amp;#34;Salary&amp;#34; &amp;#34;NewLeague&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="处理缺失值"&gt;处理缺失值&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;is.na&lt;/span&gt;(Hitters))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 59
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;删掉缺失值条目&lt;/p&gt;</description></item><item><title>ISLR实验：岭回归和lasso</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-22-islr-lab-chap06-shrinkage/</link><pubDate>Mon, 22 Feb 2021 21:21:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-22-islr-lab-chap06-shrinkage/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《6.6 实验2：岭回归和lasso》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍两种压缩估计方法&lt;/p&gt;
&lt;p&gt;使用对系数进行约束或加罚的技巧对包含 p 个预测变量的模型进行拟合，也就是说，将系数估计值往零的方向压缩。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(glmnet)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;棒球数据集，使用若干与棒球运动员上一年比赛成绩相关的变量来预测该运动员的薪水 (Salary)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; AtBat Hits HmRun Runs RBI Walks Years CAtBat CHits
-Andy Allanson 293 66 1 30 29 14 1 293 66
-Alan Ashby 315 81 7 24 38 39 14 3449 835
-Alvin Davis 479 130 18 66 72 76 3 1624 457
-Andre Dawson 496 141 20 65 78 37 11 5628 1575
-Andres Galarraga 321 87 10 39 42 30 2 396 101
-Alfredo Griffin 594 169 4 74 51 35 11 4408 1133
 CHmRun CRuns CRBI CWalks League Division PutOuts
-Andy Allanson 1 30 29 14 A E 446
-Alan Ashby 69 321 414 375 N W 632
-Alvin Davis 63 224 266 263 A W 880
-Andre Dawson 225 828 838 354 N E 200
-Andres Galarraga 12 48 46 33 N E 805
-Alfredo Griffin 19 501 336 194 A W 282
 Assists Errors Salary NewLeague
-Andy Allanson 33 20 NA A
-Alan Ashby 43 10 475.0 N
-Alvin Davis 82 14 480.0 A
-Andre Dawson 11 3 500.0 N
-Andres Galarraga 40 4 91.5 N
-Alfredo Griffin 421 25 750.0 A
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dim&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 322 20
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [1] &amp;#34;AtBat&amp;#34; &amp;#34;Hits&amp;#34; &amp;#34;HmRun&amp;#34; &amp;#34;Runs&amp;#34; &amp;#34;RBI&amp;#34; 
 [6] &amp;#34;Walks&amp;#34; &amp;#34;Years&amp;#34; &amp;#34;CAtBat&amp;#34; &amp;#34;CHits&amp;#34; &amp;#34;CHmRun&amp;#34; 
[11] &amp;#34;CRuns&amp;#34; &amp;#34;CRBI&amp;#34; &amp;#34;CWalks&amp;#34; &amp;#34;League&amp;#34; &amp;#34;Division&amp;#34; 
[16] &amp;#34;PutOuts&amp;#34; &amp;#34;Assists&amp;#34; &amp;#34;Errors&amp;#34; &amp;#34;Salary&amp;#34; &amp;#34;NewLeague&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="处理缺失值"&gt;处理缺失值&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;is.na&lt;/span&gt;(Hitters))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 59
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;删掉缺失值条目&lt;/p&gt;</description></item><item><title>ISLR实验：子集选择方法</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-21-islr-lab-chap06-subsets/</link><pubDate>Sun, 21 Feb 2021 22:13:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-21-islr-lab-chap06-subsets/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《6.5 实验1：子集选择方法》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍筛选预测变量子集的几种方法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(leaps)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;棒球数据集，使用若干与棒球运动员上一年比赛成绩相关的变量来预测该运动员的薪水 (Salary)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; AtBat Hits HmRun Runs RBI Walks Years CAtBat CHits
-Andy Allanson 293 66 1 30 29 14 1 293 66
-Alan Ashby 315 81 7 24 38 39 14 3449 835
-Alvin Davis 479 130 18 66 72 76 3 1624 457
-Andre Dawson 496 141 20 65 78 37 11 5628 1575
-Andres Galarraga 321 87 10 39 42 30 2 396 101
-Alfredo Griffin 594 169 4 74 51 35 11 4408 1133
 CHmRun CRuns CRBI CWalks League Division PutOuts
-Andy Allanson 1 30 29 14 A E 446
-Alan Ashby 69 321 414 375 N W 632
-Alvin Davis 63 224 266 263 A W 880
-Andre Dawson 225 828 838 354 N E 200
-Andres Galarraga 12 48 46 33 N E 805
-Alfredo Griffin 19 501 336 194 A W 282
 Assists Errors Salary NewLeague
-Andy Allanson 33 20 NA A
-Alan Ashby 43 10 475.0 N
-Alvin Davis 82 14 480.0 A
-Andre Dawson 11 3 500.0 N
-Andres Galarraga 40 4 91.5 N
-Alfredo Griffin 421 25 750.0 A
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dim&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 322 20
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;names&lt;/span&gt;(Hitters)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [1] &amp;#34;AtBat&amp;#34; &amp;#34;Hits&amp;#34; &amp;#34;HmRun&amp;#34; &amp;#34;Runs&amp;#34; &amp;#34;RBI&amp;#34; 
 [6] &amp;#34;Walks&amp;#34; &amp;#34;Years&amp;#34; &amp;#34;CAtBat&amp;#34; &amp;#34;CHits&amp;#34; &amp;#34;CHmRun&amp;#34; 
[11] &amp;#34;CRuns&amp;#34; &amp;#34;CRBI&amp;#34; &amp;#34;CWalks&amp;#34; &amp;#34;League&amp;#34; &amp;#34;Division&amp;#34; 
[16] &amp;#34;PutOuts&amp;#34; &amp;#34;Assists&amp;#34; &amp;#34;Errors&amp;#34; &amp;#34;Salary&amp;#34; &amp;#34;NewLeague&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="处理缺失值"&gt;处理缺失值&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;is.na&lt;/span&gt;(Hitters))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 59
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;删掉缺失值条目&lt;/p&gt;</description></item><item><title>R语言实战：广义线性模型</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-18-r-in-action-chap13-glm/</link><pubDate>Thu, 18 Feb 2021 20:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-18-r-in-action-chap13-glm/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="广义线性模型和-glm-函数"&gt;广义线性模型和 &lt;code&gt;glm()&lt;/code&gt; 函数&lt;/h2&gt;
&lt;p&gt;标准线性模型：假设 Y 呈正态分布&lt;/p&gt;
&lt;p&gt;广义线性模型：假设 Y 服从指数分布族中的一种分布&lt;/p&gt;
&lt;h3 id="glm-函数"&gt;&lt;code&gt;glm()&lt;/code&gt; 函数&lt;/h3&gt;
&lt;p&gt;基本形式&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;glm&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; formula, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; family&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;family&lt;/span&gt;(link&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Logistic 回归&lt;/strong&gt;：用于二值响应变量 (0 和 1)&lt;/p&gt;
&lt;p&gt;$$
log_{e}(\frac{\pi}{1-\pi}) = \beta_0 + \sum_{j=1}^{p}\beta_{j}X_{j}
$$&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;glm&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; X1 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; X2 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; X3, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; family&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;binomial&lt;/span&gt;(link&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;logit&amp;#34;&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mydata
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;泊松回归&lt;/strong&gt;：适用于在给定时间内响应变量为事件发生数目的情形&lt;/p&gt;
&lt;p&gt;$$
log_{e}(\lambda) = \beta_0 + \sum_{j=1}^{p}\beta_{j}X_{j}
$$&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;glm&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; X1 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; X2 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; X3, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; family&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;possion&lt;/span&gt;(link&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log&amp;#34;&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mydata
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;标准线性回归&lt;/strong&gt;：广义线性回归的一种特例&lt;/p&gt;
&lt;p&gt;$$
\mu_{Y} = \beta_0 + \sum_{j=1}^{p}\beta_{j}X_{j}
$$&lt;/p&gt;</description></item><item><title>论文阅读：ECMWF机器学习路线图2021-2030</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-11-paper-duben-2021-machine-learning-at-ecmwf/</link><pubDate>Sun, 14 Feb 2021 23:47:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-11-paper-duben-2021-machine-learning-at-ecmwf/</guid><description>&lt;p&gt;ECMWF 于 2021 年 2 月发布未来十年的机器学习路线图。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Düben, P, Modigliani, U, Geer, A, Siemen, S, Pappenberger,
F, Bauer, P, Brown, A, Palkovic, M, Raoult, B, Wedi, N, Baousis, V, 2021,
Machine learning at ECMWF: A roadmap for the next 10 years,
ECMWF Technical memorandum 878, doi: 10.21957/ge7ckgm&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文“&lt;strong&gt;正文&lt;/strong&gt;”章节简要介绍该技术文档的部分内容，底稿来自 Google 翻译，并&lt;strong&gt;结合笔者自己的理解，对部分原文进行调整、删减和重排&lt;/strong&gt;。
如有偏差，敬请批评指正。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;数值天气预报和气候服务领域的科学家正探索人工智能 (Artificial Intelligence, AI) 和机器学习 (Machine Learning, ML) 的新能力将会如何改变未来的地球系统科学。
但是，研究的范围和速度也带来一些严峻的挑战：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要建立必要的专门知识&lt;/li&gt;
&lt;li&gt;需要开发软件和硬件基础设施&lt;/li&gt;
&lt;li&gt;在预报工作流中将机器学习方法与传统模型集成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本技术报告将为未来十年 (2021-2031) 建立路线图 (roadmap)，指出所面临的挑战，提供可行的解决方案，并设定步骤。&lt;/p&gt;
&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;What, why and how&lt;/p&gt;</description></item><item><title>ISLR实验：交叉验证法和自助法</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-10-islr-lab-chap05-cv-and-boostrap/</link><pubDate>Wed, 10 Feb 2021 21:44:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-10-islr-lab-chap05-cv-and-boostrap/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《5.3 实验：交叉验证法和自助法》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="验证集方法"&gt;验证集方法&lt;/h2&gt;
&lt;p&gt;validation set approach&lt;/p&gt;
&lt;p&gt;随机将观测集分成两部分：一个训练集 (training set) 和一个验证集 (validation set)，或叫做保留集 (hold-out set)。
在训练集上拟合模型，用验证集计算错误率 (通常使用均方误差)。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Auto)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; mpg cylinders displacement horsepower weight acceleration year origin
1 18 8 307 130 3504 12.0 70 1
2 15 8 350 165 3693 11.5 70 1
3 18 8 318 150 3436 11.0 70 1
4 16 8 304 150 3433 12.0 70 1
5 17 8 302 140 3449 10.5 70 1
6 15 8 429 198 4341 10.0 70 1
 name
1 chevrolet chevelle malibu
2 buick skylark 320
3 plymouth satellite
4 amc rebel sst
5 ford torino
6 ford galaxie 500
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dim&lt;/span&gt;(Auto)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 392 9
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;随机抽取训练集，使用 &lt;code&gt;sample()&lt;/code&gt; 函数生成样本抽样序号子集。
为保证结果一致，使用 &lt;code&gt;set.seed()&lt;/code&gt; 函数设置固定的随机数种子。&lt;/p&gt;</description></item><item><title>数值预报模式不同时次运行时长是否相同？</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-06-is-running-time-of-nwp-models-the-same-at-different-cycle/</link><pubDate>Mon, 08 Feb 2021 21:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-06-is-running-time-of-nwp-models-the-same-at-different-cycle/</guid><description>&lt;p&gt;数值天气预报模式业务系统每天会运行多个时次，及时向预报员提供最新的预报结果。
大部分系统不同时次之间除了输入数据外，没有显著的区别。
那么，不同时次模式积分的运行时长是否相同呢？&lt;/p&gt;
&lt;p&gt;本文尝试使用多种方法回答这一问题。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;GRAPES 模式积分程序在日志中输出单步积分耗时，所有单步耗时累加可以得到模式积分总体耗时。&lt;/p&gt;
&lt;p&gt;下面是 GRAPES MESO 3KM 模式积分程序输出的时间步长信息，使用正则表达式提取积分步数和单步积分时长。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Timing for processing for step 3901 (2021020911:44:21): 0.74780 elapsed seconds.
Timing for processing for step 3901 (2021020911:44:21): 0.74756 cpu seconds.
 begin of gcr 9.699100979868703E-006
 RES of gcr 9.787437371783738E-013 in 21 iterations 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;详细提取方法请查看如下文章：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-06-nwpc-notebook-get-step-time-for-grapes-gfs/"&gt;NWPC笔记：获取模式积分时长 - 恒定步长&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-get-step-time-for-grapes-meso-3km/"&gt;NWPC笔记：获取模式积分时长 - 动态步长&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;本文使用 2020 年 8 月 1 日至 11 月 30 日 GRAPES GFS，GRAPES MESO 3KM 和 GRAPES TYM 三个业务系统的模式积分程序输出日志。
数据来自 NWPC 业务系统备份目录，少量时次的日志有缺失。&lt;/p&gt;</description></item><item><title>R语言实战：重抽样与自助法</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-06-r-in-action-chap12-resample-and-boostrap/</link><pubDate>Sat, 06 Feb 2021 18:13:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-06-r-in-action-chap12-resample-and-boostrap/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="置换检验"&gt;置换检验&lt;/h2&gt;
&lt;p&gt;置换检验，随机化检验，重随机化检验&lt;/p&gt;
&lt;p&gt;精确检验 vs 蒙特卡洛模拟&lt;/p&gt;
&lt;h2 id="使用-coin-包做置换检验"&gt;使用 &lt;code&gt;coin&lt;/code&gt; 包做置换检验&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;响应值与组的分配独立吗？&lt;/li&gt;
&lt;li&gt;两个数值变量独立吗？&lt;/li&gt;
&lt;li&gt;两个类别型别变量独立吗？&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(coin)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="独立两样本和-k-样本检验"&gt;独立两样本和 K 样本检验&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;score &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;58&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;57&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;62&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;65&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;treatment &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;factor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;rep&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;rep&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;my_data &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data.frame&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; treatment, score
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;my_data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; treatment score
1 A 40
2 A 57
3 A 45
4 A 55
5 A 58
6 B 57
7 B 64
8 B 55
9 B 62
10 B 65
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;t 检验，结果显著&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;t.test&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; score &lt;span style="color:#f92672"&gt;~&lt;/span&gt; treatment,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;my_data,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; var.equal&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;	Two Sample t-test

data: score by treatment
t = -2.345, df = 8, p-value = 0.04705
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -19.0405455 -0.1594545
sample estimates:
mean in group A mean in group B 
 51.0 60.6 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;置换检验，结果不显著&lt;/p&gt;</description></item><item><title>R语言实战：中级绘图</title><link>https://blog.perillaroc.wang/post/2021/02/2021-02-05-r-in-action-chap11-middle-level-plot/</link><pubDate>Fri, 05 Feb 2021 20:06:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/02/2021-02-05-r-in-action-chap11-middle-level-plot/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="散点图"&gt;散点图&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;wt, mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;mpg,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Basic Scatter plot of MPG vs. Weight&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xlab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Car Weight (lbs/1000)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ylab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Miles Per Gallon&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;19&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;abline&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(mpg&lt;span style="color:#f92672"&gt;~&lt;/span&gt;wt, data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mtcars),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;red&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lwd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;lines&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lowess&lt;/span&gt;(mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;wt, mtcars&lt;span style="color:#f92672"&gt;$&lt;/span&gt;mpg),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; col&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;blue&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lwd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/r/ria/chap11/basic-scatter.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;car&lt;/code&gt; 包的 &lt;code&gt;scatterplot()&lt;/code&gt; 函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(car)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按条件绘图&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scatterplot&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mpg &lt;span style="color:#f92672"&gt;~&lt;/span&gt; wt &lt;span style="color:#f92672"&gt;|&lt;/span&gt; cyl,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mtcars,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lwd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; smooth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(span&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.75&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Scatter Plot of MPG vs. Weight by # Cylinders&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xlab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Weight of Car (lbs/1000)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ylab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Miles Per Gallon&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; legend&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; boxplots&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;xy&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/r/ria/chap11/scatterplot.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>视界：ecFlow 5为成员国带来好处</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-31-view-ecflow-5-brings-benefits-member-states/</link><pubDate>Tue, 02 Feb 2021 23:25:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-31-view-ecflow-5-brings-benefits-member-states/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 166 - Winter 2021 由 Avi Bahra、Iain Russell 和 Sándor Kertész 撰写的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/166/computing/ecflow-5-brings-benefits-member-states"&gt;ecFlow 5 brings benefits to Member States&lt;/a&gt;》，版权归原作者所有。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;管理大规模数据密集型计算过程的工作流是一个日益严峻的挑战。
这些工作流必须是可重复，高度可用，可监视和准确的，同时仍要灵活地支持更改。
在 ECMWF，ecFlow 应对了这一挑战，ecFlow 是内部开发的工作流软件包，可以满足中心及其成员国和合作国不断变化的要求。&lt;/p&gt;
&lt;p&gt;ecFlow 面向通用用途设计，但已根据天气和气候科学的业务和研究需求进行了适配。
例如，ecFlow 在 ECMWF 有多种用途，包括研发实验运行，业务模式运行，数据后处理和归档以及软件构建。&lt;/p&gt;
&lt;p&gt;ecFlow 使用户可以在受控环境中运行大量程序，这些程序相互之间以及在时间上都有依赖关系。
它提供对硬件和软件故障的良好容忍度，并允许受控重启。
服务端，客户端和图形用户界面 (GUI) 具有高度的可伸缩性，可以处理具有数十万个任务的工作流。
ecFlow 是开源的，使用 C++ 编写以实现最佳性能。
它在 UNIX 平台上运行，在 Linux 上具有多年的经验，最近用在 macOS 上。&lt;/p&gt;
&lt;p&gt;ecFlow 的版本 5 在功能，性能，安全性和可维护性方面带来了许多现代化改进。&lt;/p&gt;
&lt;h3 id="ecflow-的架构"&gt;ecFlow 的架构&lt;/h3&gt;
&lt;p&gt;ecFlow 使用 C/S 架构 (图1)。
ecFlow 服务端管理多个套件 (suite)，每个套件都是任务的分层集合。
可以使用可确保其语法正确性的 Python API 定义复杂的套件 (图2）。
更简单的套件可以通过纯文本文件定义。
服务端将任务提交给将要运行的计算机，并在执行过程中接收更新。&lt;/p&gt;</description></item><item><title>ISLR实验：分类 - K最近邻</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-knn/</link><pubDate>Sun, 31 Jan 2021 21:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-knn/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《4.6 R实验：逻辑斯谛回归、LDA、QDA和KNN》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(class)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;股票市场数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Year Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today Direction
1 2001 0.381 -0.192 -2.624 -1.055 5.010 1.1913 0.959 Up
2 2001 0.959 0.381 -0.192 -2.624 -1.055 1.2965 1.032 Up
3 2001 1.032 0.959 0.381 -0.192 -2.624 1.4112 -0.623 Down
4 2001 -0.623 1.032 0.959 0.381 -0.192 1.2760 0.614 Up
5 2001 0.614 -0.623 1.032 0.959 0.381 1.2057 0.213 Up
6 2001 0.213 0.614 -0.623 1.032 0.959 1.3491 1.392 Up
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="训练集和测试集"&gt;训练集和测试集&lt;/h3&gt;
&lt;p&gt;训练集：2001 至 2004 年&lt;/p&gt;</description></item><item><title>ISLR实验：分类 - 二次判别分析</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-qda/</link><pubDate>Sun, 31 Jan 2021 21:17:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-qda/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《4.6 R实验：逻辑斯谛回归、LDA、QDA和KNN》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(MASS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(pROC)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;股票市场数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Year Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today Direction
1 2001 0.381 -0.192 -2.624 -1.055 5.010 1.1913 0.959 Up
2 2001 0.959 0.381 -0.192 -2.624 -1.055 1.2965 1.032 Up
3 2001 1.032 0.959 0.381 -0.192 -2.624 1.4112 -0.623 Down
4 2001 -0.623 1.032 0.959 0.381 -0.192 1.2760 0.614 Up
5 2001 0.614 -0.623 1.032 0.959 0.381 1.2057 0.213 Up
6 2001 0.213 0.614 -0.623 1.032 0.959 1.3491 1.392 Up
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="训练集和测试集"&gt;训练集和测试集&lt;/h3&gt;
&lt;p&gt;训练集：2001 至 2004 年&lt;/p&gt;</description></item><item><title>ISLR实验：分类 - 线性判别分析</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-lda/</link><pubDate>Sun, 31 Jan 2021 21:14:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-lda/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《4.6 R实验：逻辑斯谛回归、LDA、QDA和KNN》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(MASS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(pROC)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;股票市场数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Year Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today Direction
1 2001 0.381 -0.192 -2.624 -1.055 5.010 1.1913 0.959 Up
2 2001 0.959 0.381 -0.192 -2.624 -1.055 1.2965 1.032 Up
3 2001 1.032 0.959 0.381 -0.192 -2.624 1.4112 -0.623 Down
4 2001 -0.623 1.032 0.959 0.381 -0.192 1.2760 0.614 Up
5 2001 0.614 -0.623 1.032 0.959 0.381 1.2057 0.213 Up
6 2001 0.213 0.614 -0.623 1.032 0.959 1.3491 1.392 Up
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="训练集和测试集"&gt;训练集和测试集&lt;/h3&gt;
&lt;p&gt;训练集：2001 至 2004 年&lt;/p&gt;</description></item><item><title>ISLR实验：分类 - 逻辑斯谛回归</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-logistic/</link><pubDate>Sun, 31 Jan 2021 21:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-31-islr-lab-chap04-logistic/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《4.6 R实验：逻辑斯谛回归、LDA、QDA和KNN》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(corrgram)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(car)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(pROC)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;股票市场数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Year Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today Direction
1 2001 0.381 -0.192 -2.624 -1.055 5.010 1.1913 0.959 Up
2 2001 0.959 0.381 -0.192 -2.624 -1.055 1.2965 1.032 Up
3 2001 1.032 0.959 0.381 -0.192 -2.624 1.4112 -0.623 Down
4 2001 -0.623 1.032 0.959 0.381 -0.192 1.2760 0.614 Up
5 2001 0.614 -0.623 1.032 0.959 0.381 1.2057 0.213 Up
6 2001 0.213 0.614 -0.623 1.032 0.959 1.3491 1.392 Up
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dim&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 1250 9
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(Smarket)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Year Lag1 Lag2 
 Min. :2001 Min. :-4.922000 Min. :-4.922000 
 1st Qu.:2002 1st Qu.:-0.639500 1st Qu.:-0.639500 
 Median :2003 Median : 0.039000 Median : 0.039000 
 Mean :2003 Mean : 0.003834 Mean : 0.003919 
 3rd Qu.:2004 3rd Qu.: 0.596750 3rd Qu.: 0.596750 
 Max. :2005 Max. : 5.733000 Max. : 5.733000 
 Lag3 Lag4 Lag5 
 Min. :-4.922000 Min. :-4.922000 Min. :-4.92200 
 1st Qu.:-0.640000 1st Qu.:-0.640000 1st Qu.:-0.64000 
 Median : 0.038500 Median : 0.038500 Median : 0.03850 
 Mean : 0.001716 Mean : 0.001636 Mean : 0.00561 
 3rd Qu.: 0.596750 3rd Qu.: 0.596750 3rd Qu.: 0.59700 
 Max. : 5.733000 Max. : 5.733000 Max. : 5.73300 
 Volume Today Direction 
 Min. :0.3561 Min. :-4.922000 Down:602 
 1st Qu.:1.2574 1st Qu.:-0.639500 Up :648 
 Median :1.4229 Median : 0.038500 
 Mean :1.4783 Mean : 0.003138 
 3rd Qu.:1.6417 3rd Qu.: 0.596750 
 Max. :3.1525 Max. : 5.733000 
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="探索数据"&gt;探索数据&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;相关性&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>视界：新NCAR-WYOMING超级计算机将加速科学探索</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-29-view-new-ncar-wyoming-supercomputer-accelerate-scientific-discovery/</link><pubDate>Sat, 30 Jan 2021 15:02:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-29-view-new-ncar-wyoming-supercomputer-accelerate-scientific-discovery/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 UCAR 官方网站在 2021 年 1 月 27 日发布的由 DAVID HOSANSKY 撰写的文章《&lt;a href="https://news.ucar.edu/132774/new-ncar-wyoming-supercomputer-accelerate-scientific-discovery"&gt;NEW NCAR-WYOMING SUPERCOMPUTER TO ACCELERATE SCIENTIFIC DISCOVERY&lt;/a&gt;》，版权归原作者所有。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/view/NWSC%20gettelman.jpeg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在 NCAR-Wyoming 超算中心进行的可变分辨率气候模拟显示了一场登陆飓风。
科学家们可以使用功能强大的超级计算机来运行诸如 NCAR-based Community Earth System Model 之类的模型，以研究气候变化对大规模天气事件的影响。
要查看此可视化产品以及在超算上运行的模拟创建的其它可视化产品，请访问 visgallery.ucar.edu。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The National Center for Atmospheric Research (NCAR) 今天宣布，在竞争激烈的开放采购程序之后，已选择其下一代超级计算机来推进地球系统科学。
新机器将帮助科学家进行必要的研究，以更好地理解影响社会的一系列现象，从主要的森林大火到可能威胁 GPS 和其他敏感技术的太阳风暴爆发。&lt;/p&gt;
&lt;p&gt;该创新系统将由惠普 (Hewlett Packard Enterprise, HPE) 制造，并于今年在怀俄明州 Cheyenne 市的 NCAR-Wyoming 超算中心 (NWSC) 安装。
该系统将于 &lt;strong&gt;2022 年初&lt;/strong&gt; 投入运营，并将取代现有的系统 (称为 Cheyenne)。&lt;/p&gt;
&lt;p&gt;NCAR 面向怀俄明州的学生举行全州竞赛，为新系统起名。&lt;/p&gt;
&lt;p&gt;HPE-Cray EX 超级计算机将是一个 19.87 petaflops 的系统，这意味着它将具有理论上每秒执行 19.87 千万亿次计算的能力。
这几乎是 Cheyenne 超算进行科学计算速度的 3.5 倍，相当于地球上每个男人，女人和孩子每秒求解一个方程持续一个月的速度。
一旦运行，由 HPE 驱动的系统预计将跻身全球最快的超级计算机前 25 名左右之列。&lt;/p&gt;</description></item><item><title>R语言实战：方差分析</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-27-r-in-action-chap09-anova/</link><pubDate>Wed, 27 Jan 2021 22:04:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-27-r-in-action-chap09-anova/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="术语速成"&gt;术语速成&lt;/h2&gt;
&lt;p&gt;组件因子&lt;/p&gt;
&lt;p&gt;因变量 vs 自变量&lt;/p&gt;
&lt;p&gt;均衡设计 vs 非均衡设计&lt;/p&gt;
&lt;p&gt;单因素方差分析 one-way ANOVA，单因素组间方差分析&lt;/p&gt;
&lt;p&gt;组内因子&lt;/p&gt;
&lt;p&gt;单因素组内方差分析，重复测量方差分析&lt;/p&gt;
&lt;p&gt;主效应 vs 交互效应&lt;/p&gt;
&lt;p&gt;因素方差分析设计&lt;/p&gt;
&lt;p&gt;混合模型方差分析&lt;/p&gt;
&lt;p&gt;混淆因素 confounding factor&lt;/p&gt;
&lt;p&gt;干扰变数 nuisance variable&lt;/p&gt;
&lt;p&gt;协变量&lt;/p&gt;
&lt;p&gt;协方差分析 ANCOVA&lt;/p&gt;
&lt;p&gt;多元方差分析 MANOVA&lt;/p&gt;
&lt;p&gt;多元协方差分析 MANCOVA&lt;/p&gt;
&lt;h2 id="anova-模型拟合"&gt;ANOVA 模型拟合&lt;/h2&gt;
&lt;p&gt;广义线性模型的特例&lt;/p&gt;
&lt;h3 id="aov-函数"&gt;&lt;code&gt;aov()&lt;/code&gt; 函数&lt;/h3&gt;
&lt;p&gt;定量变量&lt;/p&gt;
&lt;p&gt;组别因子&lt;/p&gt;
&lt;p&gt;标识变量&lt;/p&gt;
&lt;h3 id="表达式中各项的顺序"&gt;表达式中各项的顺序&lt;/h3&gt;
&lt;p&gt;类型1：序贯型（默认）&lt;/p&gt;
&lt;p&gt;类型2：分层型&lt;/p&gt;
&lt;p&gt;类型3：边界型&lt;/p&gt;
&lt;p&gt;&lt;code&gt;car&lt;/code&gt; 包的 &lt;code&gt;Anova()&lt;/code&gt; 函数&lt;/p&gt;
&lt;h2 id="单因素方差分析"&gt;单因素方差分析&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(multcomp)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(cholesterol)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; trt response
1 1time 3.8612
2 1time 10.3868
3 1time 5.9059
4 1time 3.0609
5 1time 7.7204
6 1time 2.7139
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(cholesterol)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;table&lt;/span&gt;(trt)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;trt
 1time 2times 4times drugD drugE 
 10 10 10 10 10
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;aggregate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; by&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(trt),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FUN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mean
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Group.1 x
1 1time 5.78197
2 2times 9.22497
3 4times 12.37478
4 drugD 15.36117
5 drugE 20.94752
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;aggregate&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; by&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(trt),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FUN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Group.1 x
1 1time 2.878113
2 2times 3.483054
3 4times 2.923119
4 drugD 3.454636
5 drugE 3.345003
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fit &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aov&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response &lt;span style="color:#f92672"&gt;~&lt;/span&gt; trt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(fit)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Df Sum Sq Mean Sq F value Pr(&amp;gt;F) 
trt 4 1351.4 337.8 32.43 9.82e-13 ***
Residuals 45 468.8 10.4 
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(gplots)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;绘制各组均值及置信区间&lt;/p&gt;</description></item><item><title>R语言实战：回归</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-14-r-in-action-chap08-regression/</link><pubDate>Thu, 14 Jan 2021 21:13:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-14-r-in-action-chap08-regression/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="回归的多面性"&gt;回归的多面性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;简单线性&lt;/li&gt;
&lt;li&gt;多项式&lt;/li&gt;
&lt;li&gt;多层&lt;/li&gt;
&lt;li&gt;多元线性&lt;/li&gt;
&lt;li&gt;多变量&lt;/li&gt;
&lt;li&gt;Logistic&lt;/li&gt;
&lt;li&gt;泊松&lt;/li&gt;
&lt;li&gt;Cox比例风险&lt;/li&gt;
&lt;li&gt;时间序列&lt;/li&gt;
&lt;li&gt;非线性&lt;/li&gt;
&lt;li&gt;非参数&lt;/li&gt;
&lt;li&gt;稳健&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;普通最小二乘 (OLS) 回归法，包括简单线性回归，多项式回归和多元线性回归。&lt;/p&gt;
&lt;h3 id="ols-回归的适用情景"&gt;OLS 回归的适用情景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;发现有趣的问题&lt;/li&gt;
&lt;li&gt;设计一个有用的、可以测量的响应变量&lt;/li&gt;
&lt;li&gt;收集合适的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="基础回顾"&gt;基础回顾&lt;/h3&gt;
&lt;h2 id="ols-回归"&gt;OLS 回归&lt;/h2&gt;
&lt;p&gt;$$
\hat{Y_i}=\hat{\beta_0} + \hat{\beta_1}X_{1i} + &amp;hellip; + \hat{\beta_k}X_{ki}
$$&lt;/p&gt;
&lt;p&gt;残差平方和最小&lt;/p&gt;
&lt;p&gt;$$
\sum_{i=1}^{n}(Y_i-\hat{Y_i})^2=\sum_{i=1}^{n}(Y_i-\hat{\beta_0}+\hat{\beta_1}X_{1i}+&amp;hellip;+\hat{\beta_k}X_{ki})=\sum_{i=1}^{n}\epsilon_i^2
$$&lt;/p&gt;
&lt;p&gt;统计假设&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正态性：对于固定的自变量值，因变量值成正态分布&lt;/li&gt;
&lt;li&gt;独立性：Y_i 值之间相互独立&lt;/li&gt;
&lt;li&gt;线性：因变量与自变量之间为线性相关&lt;/li&gt;
&lt;li&gt;同方差性：因变量的方差不随自变量的水平不同而变化&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="用-lm-拟合回归模型"&gt;用 &lt;code&gt;lm()&lt;/code&gt; 拟合回归模型&lt;/h3&gt;
&lt;p&gt;简单线性回归&lt;/p&gt;
&lt;p&gt;多项式回归&lt;/p&gt;
&lt;p&gt;多元线性回归&lt;/p&gt;
&lt;h3 id="简单线性回归"&gt;简单线性回归&lt;/h3&gt;
&lt;p&gt;数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(women)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; height weight
1 58 115
2 59 117
3 60 120
4 61 123
5 62 126
6 63 129
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;summary()&lt;/code&gt; 函数&lt;/p&gt;</description></item><item><title>ISLR习题：线性回归 - Boston数据集</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-boston/</link><pubDate>Wed, 13 Jan 2021 21:51:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-boston/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 第三章习题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Boston 数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(MASS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(Boston)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Boston)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; crim zn indus chas nox rm age dis rad tax ptratio black lstat medv
1 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98 24.0
2 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6
3 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7
4 0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94 33.4
5 0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 5.33 36.2
6 0.02985 0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21 28.7
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="简单线性回归"&gt;简单线性回归&lt;/h2&gt;
&lt;h3 id="zn"&gt;zn&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_zn &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(crim &lt;span style="color:#f92672"&gt;~&lt;/span&gt; zn)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_zn)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = crim ~ zn)

Residuals:
 Min 1Q Median 3Q Max 
-4.429 -4.222 -2.620 1.250 84.523 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) 4.45369 0.41722 10.675 &amp;lt; 2e-16 ***
zn -0.07393 0.01609 -4.594 5.51e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.435 on 504 degrees of freedom
Multiple R-squared: 0.04019,	Adjusted R-squared: 0.03828 
F-statistic: 21.1 on 1 and 504 DF, p-value: 5.506e-06
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="indus"&gt;indus&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_indus &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(crim &lt;span style="color:#f92672"&gt;~&lt;/span&gt; indus)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_indus)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = crim ~ indus)

Residuals:
 Min 1Q Median 3Q Max 
-11.972 -2.698 -0.736 0.712 81.813 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) -2.06374 0.66723 -3.093 0.00209 ** 
indus 0.50978 0.05102 9.991 &amp;lt; 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 7.866 on 504 degrees of freedom
Multiple R-squared: 0.1653,	Adjusted R-squared: 0.1637 
F-statistic: 99.82 on 1 and 504 DF, p-value: &amp;lt; 2.2e-16
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="chas"&gt;chas&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_chas &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(crim &lt;span style="color:#f92672"&gt;~&lt;/span&gt; chas)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_chas)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = crim ~ chas)

Residuals:
 Min 1Q Median 3Q Max 
-3.738 -3.661 -3.435 0.018 85.232 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) 3.7444 0.3961 9.453 &amp;lt;2e-16 ***
chas -1.8928 1.5061 -1.257 0.209 
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 8.597 on 504 degrees of freedom
Multiple R-squared: 0.003124,	Adjusted R-squared: 0.001146 
F-statistic: 1.579 on 1 and 504 DF, p-value: 0.2094
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;没有显著性&lt;/p&gt;</description></item><item><title>ISLR习题：线性回归 - 共线性问题</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-colinear/</link><pubDate>Wed, 13 Jan 2021 21:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-colinear/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 第三章习题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;创建一组有共线性关系的数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;set.seed&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x1 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;runif&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x2 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.5&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; x1 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; x1 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; x2 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;$$
y = 2 + 2x_1 + 0.3x_2
$$&lt;/p&gt;
&lt;h2 id="相关性"&gt;相关性&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cor&lt;/span&gt;(x1, x2)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 0.9469723
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(x1, x2)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/islr/app/chap03/colinear/scatter.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="拟合"&gt;拟合&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_v1 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; x1 &lt;span style="color:#f92672"&gt;+&lt;/span&gt; x2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_v1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = y ~ x1 + x2)

Residuals:
 Min 1Q Median 3Q Max 
-2.8311 -0.7273 -0.0537 0.6338 2.3359 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) 1.7757 0.5933 2.993 0.00351 **
x1 1.0847 1.2346 0.879 0.38179 
x2 1.0097 1.1337 0.891 0.37536 
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.056 on 97 degrees of freedom
Multiple R-squared: 0.2333,	Adjusted R-squared: 0.2175 
F-statistic: 14.76 on 2 and 97 DF, p-value: 2.54e-06
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;预测的 beta_1 和 beta_2 与真实值相差过大&lt;/p&gt;</description></item><item><title>ISLR习题：线性回归 - 线性模型的随机误差</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-eps/</link><pubDate>Wed, 13 Jan 2021 21:16:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-eps/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 第三章习题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;向量 x，eps&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;set.seed&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eps &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.25&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成向量 y&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;-1&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.25&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; eps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;beta_0 = -1&lt;/li&gt;
&lt;li&gt;beta_1 = 0.25&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="散点图"&gt;散点图&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/islr/app/chap03/eps/scatter.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="线性拟合"&gt;线性拟合&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_v1 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_v1)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = y ~ x)

Residuals:
 Min 1Q Median 3Q Max 
-0.46921 -0.15344 -0.03487 0.13485 0.58654 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) -1.00942 0.02425 -41.631 &amp;lt; 2e-16 ***
x 0.24973 0.02693 9.273 4.58e-15 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2407 on 98 degrees of freedom
Multiple R-squared: 0.4674,	Adjusted R-squared: 0.4619 
F-statistic: 85.99 on 1 and 98 DF, p-value: 4.583e-15
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;拟合得到的系数与真实值比较接近&lt;/p&gt;</description></item><item><title>ISLR习题：线性回归 - 没有截距的简单线性回归</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-none-intercept/</link><pubDate>Wed, 13 Jan 2021 21:04:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-none-intercept/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 第三章习题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;生成预测变量 x 和响应变量 y&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;set.seed&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="y-对-x"&gt;y 对 x&lt;/h2&gt;
&lt;p&gt;建立 y 对 x 的不含截距的简单线性回归&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_y_x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_y_x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = y ~ x + 0)

Residuals:
 Min 1Q Median 3Q Max 
-1.9154 -0.6472 -0.1771 0.5056 2.3109 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
x 1.9939 0.1065 18.73 &amp;lt;2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9586 on 99 degrees of freedom
Multiple R-squared: 0.7798,	Adjusted R-squared: 0.7776 
F-statistic: 350.7 on 1 and 99 DF, p-value: &amp;lt; 2.2e-16
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="x-对-y"&gt;x 对 y&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_x_y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(x &lt;span style="color:#f92672"&gt;~&lt;/span&gt; y &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_x_y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = x ~ y + 0)

Residuals:
 Min 1Q Median 3Q Max 
-0.8699 -0.2368 0.1030 0.2858 0.8938 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
y 0.39111 0.02089 18.73 &amp;lt;2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4246 on 99 degrees of freedom
Multiple R-squared: 0.7798,	Adjusted R-squared: 0.7776 
F-statistic: 350.7 on 1 and 99 DF, p-value: &amp;lt; 2.2e-16
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="对比"&gt;对比&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模型&lt;/th&gt;
					&lt;th&gt;系数&lt;/th&gt;
					&lt;th&gt;标准差&lt;/th&gt;
					&lt;th&gt;t 统计量&lt;/th&gt;
					&lt;th&gt;p 值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;y ~ x + 0&lt;/td&gt;
					&lt;td&gt;1.9939&lt;/td&gt;
					&lt;td&gt;0.1065&lt;/td&gt;
					&lt;td&gt;18.73&lt;/td&gt;
					&lt;td&gt;&amp;lt; 2.2e-16&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;x ~ y + 0&lt;/td&gt;
					&lt;td&gt;0.39111&lt;/td&gt;
					&lt;td&gt;0.02089&lt;/td&gt;
					&lt;td&gt;18.73&lt;/td&gt;
					&lt;td&gt;&amp;lt; 2.2e-16&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="t-统计量"&gt;t 统计量&lt;/h2&gt;
&lt;p&gt;第一种计算方法&lt;/p&gt;</description></item><item><title>ISLR习题：线性回归 - Carseats数据集</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-carseats/</link><pubDate>Wed, 13 Jan 2021 20:15:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-carseats/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 第三章习题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Carseats 数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Carseats)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Sales CompPrice Income Advertising Population Price ShelveLoc Age Education Urban US
1 9.50 138 73 11 276 120 Bad 42 17 Yes Yes
2 11.22 111 48 16 260 83 Good 65 10 Yes Yes
3 10.06 113 35 10 269 80 Medium 59 12 Yes Yes
4 7.40 117 100 4 466 97 Medium 55 14 Yes Yes
5 4.15 141 64 3 340 128 Bad 38 13 Yes No
6 10.81 124 113 13 501 72 Bad 78 16 No Yes
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nrow&lt;/span&gt;(Carseats)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 400
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="多元回归"&gt;多元回归&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_fit_multi &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Sales &lt;span style="color:#f92672"&gt;~&lt;/span&gt; Price &lt;span style="color:#f92672"&gt;+&lt;/span&gt; Urban &lt;span style="color:#f92672"&gt;+&lt;/span&gt; US,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Carseats
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm_fit_multi)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = Sales ~ Price + Urban + US, data = Carseats)

Residuals:
 Min 1Q Median 3Q Max 
-6.9206 -1.6220 -0.0564 1.5786 7.0581 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) 13.043469 0.651012 20.036 &amp;lt; 2e-16 ***
Price -0.054459 0.005242 -10.389 &amp;lt; 2e-16 ***
UrbanYes -0.021916 0.271650 -0.081 0.936 
USYes 1.200573 0.259042 4.635 4.86e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.472 on 396 degrees of freedom
Multiple R-squared: 0.2393,	Adjusted R-squared: 0.2335 
F-statistic: 41.52 on 3 and 396 DF, p-value: &amp;lt; 2.2e-16
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="解释系数"&gt;解释系数&lt;/h2&gt;
&lt;p&gt;Price 是数值量，与 Sales 呈负相关。&lt;/p&gt;</description></item><item><title>ISLR习题：线性回归 - Auto数据集</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-auto/</link><pubDate>Wed, 13 Jan 2021 20:05:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-13-islr-app-chap03-auto/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 第三章习题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Auto)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; mpg cylinders displacement horsepower weight acceleration year origin name
1 18 8 307 130 3504 12.0 70 1 chevrolet chevelle malibu
2 15 8 350 165 3693 11.5 70 1 buick skylark 320
3 18 8 318 150 3436 11.0 70 1 plymouth satellite
4 16 8 304 150 3433 12.0 70 1 amc rebel sst
5 17 8 302 140 3449 10.5 70 1 ford torino
6 15 8 429 198 4341 10.0 70 1 ford galaxie 500
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(Auto)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="简单线性回归"&gt;简单线性回归&lt;/h2&gt;
&lt;p&gt;mpg (油耗) 是响应变量，horsepower (马力) 是预测变量&lt;/p&gt;</description></item><item><title>新的一年要有新的开始</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-08-new-year-should-have-a-new-start/</link><pubDate>Fri, 08 Jan 2021 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-08-new-year-should-have-a-new-start/</guid><description>&lt;blockquote&gt;
&lt;p&gt;发表在公众号上的一篇文章，仅做记录。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;虽然今天为开会准备了发言，可惜我在面对突发事件的处理上一直有些问题，在关键时刻往往做出不恰当的选择。下午的发言没有按照原定的计划完整表述观点，而将对科室的建议转为对领导的“批评”。如果我以后还有机会进行类似的发言，还是要特别注意一下自己发言的目标和表述方式，可能这是最后一次如此直白地进行“批评”了。&lt;/p&gt;
&lt;p&gt;最近一段时间我对运维工作进行了很多思考，在这个公众号中写了不少相关文章，也删了很多不合时宜的文章。实际上花了这么多时间思考，也应该得出一个具体的结论，为这个问题画上一个句号。想到昨天晚上睡觉时还在想今天该如何发言，我就该意识到，如果再继续在这个问题上纠结不清，就会影响身心健康了。&lt;/p&gt;
&lt;p&gt;这个公众号本来应该是对技术工作的学习记录，而不该掺杂对工作和生活中某些小事的牢骚。我应该将关注的重心回归到工作和学习中。既然已经对运维工作有所结论，也对第一季度的工作有所计划，就应该沿着自己规划的路向前走下去。只要不断尝试不断修正，总能找到一条适合自己的路。无论我的工作是否得到认可，我只求自己问心无愧。&lt;/p&gt;
&lt;p&gt;新的一年应该有新的开始。&lt;/p&gt;</description></item><item><title>HPC上安装R语言环境</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-08-install-r-in-cma-pi/</link><pubDate>Fri, 08 Jan 2021 20:16:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-08-install-r-in-cma-pi/</guid><description>&lt;blockquote&gt;
&lt;p&gt;注：CMA-PI 上已于 2021 年 1 月 12 日安装 R 4.0.3 版本，可以直接使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CMA-PI 上 R 语言目前只有 3.2.1 版本，要使用最新的 4.0.3 版本，需要用户自行安装。&lt;/p&gt;
&lt;p&gt;R 语言二进制安装包需要管理员权限，普通用户在 HPC 中安装 R 环境需要下载源码并编译。&lt;/p&gt;
&lt;p&gt;从官网上下载 4.0.3 版本源码并解压，按如下的命令方法编译。&lt;/p&gt;
&lt;p&gt;注：PyCharm 的 R 插件需要使用 R 语言动态库，所以配置命令中使用 &lt;code&gt;--enable-R-shlib&lt;/code&gt; 选项。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module load mathlib/pcre/8.42/gnu
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module load compiler/gnu/7.2.0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/g11/wangdp/lang/R/4.0.3/install --with-pcre1 --enable-R-shlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make -j8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仿照 apps/R/3.2.1，为编译的 R 环境配置 modulefile。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#%Module1.0
module-whatis R dev toolkit..
setenv APPS_ROOT /g11/wangdp/lang/R/4.0.3/install
prepend-path PATH /g11/wangdp/lang/R/4.0.3/install/bin
prepend-path MANPATH /g11/wangdp/lang/R/4.0.3/install/share/man
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;PyCharm 的 R 插件需要设置 R 解释器的路径，我将其设置为一个单独创建的脚本 &lt;code&gt;R.sh&lt;/code&gt;，首先加载需要的环境，再执行 R 命令。&lt;/p&gt;</description></item><item><title>R语言实战：基本统计分析</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-07-r-in-action-basic-statistics/</link><pubDate>Thu, 07 Jan 2021 22:50:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-07-r-in-action-basic-statistics/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="描述性统计分析"&gt;描述性统计分析&lt;/h2&gt;
&lt;p&gt;mtcars 数据集中的三个连续变量&lt;/p&gt;
&lt;p&gt;mpg：每加仑汽油行驶英里数&lt;/p&gt;
&lt;p&gt;hp：马力&lt;/p&gt;
&lt;p&gt;wt：车重&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;selected_variables &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mpg&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;hp&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;wt&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(mtcars[selected_variables])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; mpg hp wt
Mazda RX4 21.0 110 2.620
Mazda RX4 Wag 21.0 110 2.875
Datsun 710 22.8 93 2.320
Hornet 4 Drive 21.4 110 3.215
Hornet Sportabout 18.7 175 3.440
Valiant 18.1 105 3.460
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;两个分类变量&lt;/p&gt;
&lt;p&gt;am：变速箱类型&lt;/p&gt;
&lt;p&gt;cyl：汽缸数&lt;/p&gt;
&lt;h3 id="方法云集"&gt;方法云集&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(mtcars[selected_variables])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; mpg hp wt 
 Min. :10.40 Min. : 52.0 Min. :1.513 
 1st Qu.:15.43 1st Qu.: 96.5 1st Qu.:2.581 
 Median :19.20 Median :123.0 Median :3.325 
 Mean :20.09 Mean :146.7 Mean :3.217 
 3rd Qu.:22.80 3rd Qu.:180.0 3rd Qu.:3.610 
 Max. :33.90 Max. :335.0 Max. :5.424 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;sapply()&lt;/code&gt; 函数格式&lt;/p&gt;</description></item><item><title>NWPC消息平台：运行状态分析算法</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-05-nwpc-message-task-situation-dfs-for-ecflow-client-message/</link><pubDate>Thu, 07 Jan 2021 13:39:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-05-nwpc-message-task-situation-dfs-for-ecflow-client-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;NWPC 的数值预报业务系统使用工作流软件 ecFlow 搭建，每个业务系统由大量有依赖关系的任务组成。
NWPC 消息平台为 ecFlow 系统设计运行状态变化消息，记录业务系统中每个任务的运行状态变化信息。
每天滚动循环中，每个任务会产生多条状态变化消息记录，形成一个状态变化序列。
值班人员更关心某个时次某个任务的运行情况，比如运行的起止时间，运行持续时间等具体信息。
虽然可以从状态变化序列中人工计算得到，ecFlow UI 中也提供了类似的统计功能，但这两种方式仅适合对有限任务进行少量分析。
为了实现对长时间序列的批量分析，需要设计一种自动分析运行状态的方法。&lt;/p&gt;
&lt;p&gt;本文设计并实现一种基于确定有限状态自动机的业务系统运行状态分析算法，可以计算任意任务的运行情况。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;本文使用 NWPC 消息平台生成的运行状态变化状态消息作为输入数据。&lt;/p&gt;
&lt;p&gt;消息示例如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;app&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;nwpc-message-client&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;ecflow-client&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;time&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;2021-01-01T04:51:15.825482366Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;data&amp;#34;&lt;/span&gt; : {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;args&amp;#34;&lt;/span&gt; : [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;27949969&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;command&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;init&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ecf_date&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;20210101&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ecf_host&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;login_b01&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ecf_name&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;/globalchartos/00/deterministic/base/024/wmc_humidity_700_sep_024&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ecf_port&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;31071&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ecf_rid&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;27949969&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ecf_tryno&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;envs&amp;#34;&lt;/span&gt; : &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;time&lt;/code&gt; 表示事件发生的时间&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data.command&lt;/code&gt; 表示任务的状态变化&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data.ecf_name&lt;/code&gt; 表示 ecFlow 中任务节点路径&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data.ecf_date&lt;/code&gt; 表示任务运行的日期&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个运行正常的任务的状态变化序列如下所示。
第 1 个字段是当前系统日期，第 2-3 字段是事件发生的时间，最后一个字段是状态变化类型。&lt;/p&gt;</description></item><item><title>ElasticSearch使用Scroll检索大规模数据</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-05-elasticsearch-scroll-api-for-large-query/</link><pubDate>Tue, 05 Jan 2021 14:32:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-05-elasticsearch-scroll-api-for-large-query/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;默认配置下 ElasticSearch 单个查询只能返回一页 (page) 数据，默认一页大小为 10000。
想要检索大规模数据，有多种方式。
本文介绍使用 scroll API 获取大规模数据的方法。&lt;/p&gt;
&lt;h2 id="标准查询"&gt;标准查询&lt;/h2&gt;
&lt;p&gt;查询 2020 年 12 月 GRAPES TYM 系统的所有产品消息。
TYM 系统一天运行 4 次，每个时次生成 121 个产品，理论上 12 月一共有 4 * 121 * 31 = 15004 个消息。&lt;/p&gt;
&lt;p&gt;请求 API&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;POST /2020-12/_search
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请求体&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;term&amp;#34;&lt;/span&gt; : {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;data.system&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_tym&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;sort&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;asc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查询结果如下 (省略返回条目)。
可以看到只查询到 10000 个结果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;took&amp;#34;&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;timed_out&amp;#34;&lt;/span&gt; : &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;_shards&amp;#34;&lt;/span&gt; : {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;total&amp;#34;&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;successful&amp;#34;&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;skipped&amp;#34;&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;failed&amp;#34;&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;hits&amp;#34;&lt;/span&gt; : {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;total&amp;#34;&lt;/span&gt; : {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;value&amp;#34;&lt;/span&gt; : &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;relation&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;gte&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;max_score&amp;#34;&lt;/span&gt; : &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;hits&amp;#34;&lt;/span&gt; : [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;...skip...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="scroll-查询"&gt;Scroll 查询&lt;/h2&gt;
&lt;p&gt;ElasticSearch 提供 Scroll API 支持使用单个查询返回大量数据，甚至可以返回数据全集，
类似关系型数据库中的 curser。&lt;/p&gt;</description></item><item><title>R语言实战：基本图形</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-04-r-in-action-chap06-basic-plot/</link><pubDate>Mon, 04 Jan 2021 22:22:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-04-r-in-action-chap06-basic-plot/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="条形图"&gt;条形图&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;vcd&lt;/code&gt; 包的 &lt;code&gt;Arthritis&lt;/code&gt; 数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(vcd)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(Arthritis)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; ID Treatment Sex Age Improved
1 57 Treated Male 27 Some
2 46 Treated Male 29 None
3 77 Treated Male 30 None
4 17 Treated Male 32 Marked
5 36 Treated Male 46 Marked
6 23 Treated Male 58 Marked
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="简单条形图"&gt;简单条形图&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;barplot()&lt;/code&gt; 函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counts &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;table&lt;/span&gt;(Arthritis&lt;span style="color:#f92672"&gt;$&lt;/span&gt;Improved)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; None Some Marked 
 42 14 28 
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;barplot&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; counts,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Simple Bar Plot&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xlab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Improvement&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ylab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Frequency&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2021/r/ria/chap06/simple-bar-plot.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>关于数值预报业务系统运维的讨论会</title><link>https://blog.perillaroc.wang/post/2021/01/2021-01-04-slience-is-gold/</link><pubDate>Mon, 04 Jan 2021 21:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2021/01/2021-01-04-slience-is-gold/</guid><description>&lt;blockquote&gt;
&lt;p&gt;多闻阙疑，慎言其余，则寡尤；多见阙殆，慎行其余，则寡悔。言寡尤，行寡悔，禄在其中矣。&lt;/p&gt;
&lt;p&gt;&amp;ndash;《论语》为政篇&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天下午科里值班同事与领导座谈业务系统值班，讨论很&lt;strong&gt;热烈&lt;/strong&gt;，晚上六点才因时间太晚而结束。&lt;/p&gt;
&lt;p&gt;我关注的焦点在于减少在业务系统建设和运维方面的工作量，从而将精力投入到其它更容易产出成果的方面，比如研发支撑等。
而解决问题的关键就是这部分工作能否向第三方转移，无论第三方是单位内部其它科室，还是外部公司。&lt;/p&gt;
&lt;p&gt;单位内部因为职责划分等问题，从近一两年的多次尝试来看，没有太大可能让其他科室从事业务系统建设和运维工作。
而聘请外部公司虽然需要承担昂贵的用人成本，也需要考虑经费使用的合理性，但仍是目前最可行的解决方案。
今年已着手尝试，实际效果有待后续进一步观察。&lt;/p&gt;
&lt;p&gt;过去的一年，尤其是年底阶段对运维工作的思考，让我逐步意识到，长期从事系统运维工作会带来隐性压力，对工作和生活都会产生负面影响。
我对运维工作的整体态度也从&lt;strong&gt;使用技术手段提高系统自动化运维水平&lt;/strong&gt;，变为&lt;strong&gt;通过多种方式减少系统建设和运维任务总量&lt;/strong&gt;。
单纯通过在目前值班人员中间调整任务分工，而不改变任务总量，可能会降低特定时间段内的工作量，但很难改变运维工作带来的隐性压力。
毕竟蛋糕大小没变，无论用什么方法切分，最后每人分到的都一样多。&lt;/p&gt;
&lt;p&gt;大家在讨论中提出了多项建议，有三条建议很值得关注，因为半年前就已经提过一次，而我也对此持保留态度：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;调整值班排班，改为 1 人 1 天 24 小时，休息 2 天&lt;/li&gt;
&lt;li&gt;引入定量评价机制，参考预报员评分机制，评价值班效果，并与绩效挂钩&lt;/li&gt;
&lt;li&gt;为防止意外因素，由系统单人负责制改为多人合作建设&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我认为，前两点的调整思路是通过强化责任感调动主观能动性，通过外部约束和激励来促使值班人员保障业务系统运行不出错。
我一贯认为这种通过约束行为人提高运维质量的方式不是可持续的，会给本来就承担巨大压力的运维人员带来更大的制度压力。
而且将数值预报业务系统运维工作与预报员相比较也明显不合理。
预报员队伍更加庞大，几乎每年都有新鲜力量加入，也有健全的独立于职称的评价机制。
将预报员评分思想用于仅有 7 人的值班团队，有点儿大材小用，也与部门其他科室的评价机制差别太大。&lt;/p&gt;
&lt;p&gt;第三点源于降低业务系统的维护风险，避免因负责人无法工作而导致业务系统无法变更维护。
实际上虽然单人负责制有各种各样的问题，但任何制度的形成都是有原因的。
就拿我个人来说，目前负责 4 个模式的后处理系统 (GRAPES GFS，GRAPES MESO 10KM，GRAPES MESO 3KM，GRAPES MESO 1KM) 以及 1 个模式的全流程 (GRAPES TYM)。
虽然我负责的系统往往比模式预报系统简单，但我还是要提一个问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;建设业务系统真的有那么&lt;strong&gt;困难&lt;/strong&gt;吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我只是觉得可能我们整天忙于业务和科研，而忽略从工程角度完善业务系统。
比如提供完善的说明文档，可以以最快速度将科研系统转为业务系统；
比如制定统一的系统建设规范，共享模块，所有系统都派生自一套模板；
比如通过中试平台让科研和业务使用同一套系统，减少科研到业务的转化成本。&lt;/p&gt;
&lt;p&gt;多人建系统确实能解决一部分现有问题，但解决不了核心矛盾，工作效率也不会有质的飞跃。
另外，想到已经负责这么多系统，还要花时间熟悉并建设额外的系统，那还有时间进行其它工作了么？&lt;/p&gt;
&lt;p&gt;所以正如我在之前一篇文章中说的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;科研工作它难道不香么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;很遗憾，再一次在会后发现自己说多了。
没有从之前的讨论中吸取经验教训，忘了参加讨论的第一原则：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;沉默是金。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;或许我应该在这里多写些想法，这样在实际讨论中就不会多说话了。&lt;/p&gt;
&lt;p&gt;千言万语汇成一句话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;服从中心和领导安排，做到指哪打哪&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>2020年第四季度工作总结</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-31-2020-q4-summary/</link><pubDate>Thu, 31 Dec 2020 18:19:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-31-2020-q4-summary/</guid><description>&lt;blockquote&gt;
&lt;p&gt;一鼓作气，再而衰，三而竭&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本以为第四季度会给 2020 年画上一个圆满的句号，没想到却变成对是否走在正确道路上的思考，也为 2021 年留下更多未完成的任务。&lt;/p&gt;
&lt;h2 id="系统建设"&gt;系统建设&lt;/h2&gt;
&lt;h3 id="grapes-meso-1km-后处理系统"&gt;GRAPES MESO 1KM 后处理系统&lt;/h3&gt;
&lt;p&gt;新建 GRAPES MESO 1KM 的产品后处理系统 grapes_meso_1km_post，为冬奥示范项目提供逐 3 小时生成的 24 小时预报数据产品。
相比于常规的 GRAPES 系列后处理系统，1KM POST 系统结构更简单，仅生成数据产品。
但 1KM POST 生成一些全时效的数据产品，所以系统中将分时效产品和全时效产品任务放到不同的 family 中 (hours 和 total)。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/q4/grapes-meso-1km-post-suite.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;grapes_meso_1km_post 系统，hours 生成逐时效产品，total 生成全时效产品&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="nmc-台风报文检索"&gt;NMC 台风报文检索&lt;/h3&gt;
&lt;p&gt;第二季度开发 NMC 台风数据库检索台风报文数据的 Python 程序。
因为 CMA-PI 上的 Python 环境缺乏数据库连接组件，所以脚本使用笔者自己搭建的一套环境。
而依赖于个人账户文件的程序无法在业务系统中应用，所以第四季度使用 GOLANG 重新实现报文检索程序。&lt;/p&gt;
&lt;p&gt;程序使用 SQLX 库连接 MySQL 数据库，详情参见如下文章&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/10/2020-10-30-golang-run-sql-statement-using-sqlx/"&gt;GOLANG：使用SQLX库执行简单的SQL语句&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;项目地址：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nmc-typhoon-db-client"&gt;https://github.com/nwpc-oper/nmc-typhoon-db-client&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="其他更新"&gt;其他更新&lt;/h3&gt;
&lt;p&gt;增加文件删除代码，删除 globalchartos 系统中遗漏的历史图片文件。&lt;/p&gt;
&lt;p&gt;因虚拟机升级，修改三个系统的部分 FTP 地址。&lt;/p&gt;</description></item><item><title>R语言实战：高级数据管理</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-30-r-in-action-chap05-advanced-data-operation/</link><pubDate>Wed, 30 Dec 2020 19:42:50 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-30-r-in-action-chap05-advanced-data-operation/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="数值和字符处理函数"&gt;数值和字符处理函数&lt;/h2&gt;
&lt;h3 id="统计函数"&gt;统计函数&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 1 2 3 4 5 6 7 8
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;简化版本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mean&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 4.5
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sd&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 2.44949
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;冗长版本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;n &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;meanx &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;(x) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;meanx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 4.5
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;css &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;((x &lt;span style="color:#f92672"&gt;-&lt;/span&gt; meanx)^2)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sdx &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sqrt&lt;/span&gt;(css &lt;span style="color:#f92672"&gt;/&lt;/span&gt; (n &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sdx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 2.44949
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;scale()&lt;/code&gt; 函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scale&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1]
[1,] -1.4288690
[2,] -1.0206207
[3,] -0.6123724
[4,] -0.2041241
[5,] 0.2041241
[6,] 0.6123724
[7,] 1.0206207
[8,] 1.4288690
attr(,&amp;#34;scaled:center&amp;#34;)
[1] 4.5
attr(,&amp;#34;scaled:scale&amp;#34;)
[1] 2.44949
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="概率函数"&gt;概率函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt;：密度函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt;：分布函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;q&lt;/code&gt;：分位数函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;：随机数&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;runif&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 0.3368141 0.3301134 0.9172243 0.7132270 0.5433076
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;runif&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 0.5018690 0.5012920 0.2691537 0.1911182 0.1047126
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;set.seed()&lt;/code&gt; 设置随机数种子&lt;/p&gt;</description></item><item><title>适用于NMC监控平台的数值预报产品消息</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-30-nwpc-message-production-message-for-nmc-monitor/</link><pubDate>Wed, 30 Dec 2020 19:37:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-30-nwpc-message-production-message-for-nmc-monitor/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NMC 建立了统一的业务监控平台，基于消息中间件 Kafka 实现消息系统，同时制定了统一的日志数据格式。&lt;/p&gt;
&lt;p&gt;之前已根据上一版消息规范制定产品消息格式，详情参见《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-23-nwpc-production-message-for-nmc-monitor/"&gt;适用于NMC监控平台的数值预报产品消息&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;本文介绍在新版标准下设计的数值预报产品消息格式。&lt;/p&gt;
&lt;h2 id="新旧消息对比"&gt;新旧消息对比&lt;/h2&gt;
&lt;p&gt;新版消息的目标是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;设计一套通用性较高的消息体模型，
考虑与重要产品监视系统、消息分析数据库对接的便捷性和可用性，并考虑信息的扩展能力&lt;/p&gt;
&lt;p&gt;注：摘自规范文档，略有修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;新版消息增加大量字段，并对原有字段进行修改和扩充。
数值预报产品使用的新旧两版消息格式对比如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/nmc-monitor-message/nmc-monitor-message-v2.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;2021版消息与2020版消息格式对比&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;笔者认为新增字段中的核心是用于确定消息唯一性的 &lt;code&gt;PID&lt;/code&gt; 和 &lt;code&gt;ID&lt;/code&gt;，这样后端存储就不需要用额外的机制来区别重复的消息。&lt;/p&gt;
&lt;h2 id="日志消息格式"&gt;日志消息格式&lt;/h2&gt;
&lt;p&gt;日志消息格式参见《国家气象中心消息体设计方案V1.4》。&lt;/p&gt;
&lt;p&gt;消息使用 JSON 格式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;sourceIP&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;PID&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ID&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;datetime&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;fileNames&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;absoluteDataName&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;fileSizes&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;result&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;resultDesc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各个字段的说明如下表所示。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;字段名&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;可选&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;topic&lt;/td&gt;
					&lt;td&gt;消息主题&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串（区分大小写）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;source&lt;/td&gt;
					&lt;td&gt;消息来源系统&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串（区分大小写）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;sourceIP&lt;/td&gt;
					&lt;td&gt;消息来源系统 IP&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串（区分大小写）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;PID&lt;/td&gt;
					&lt;td&gt;产品唯一标志码&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ID&lt;/td&gt;
					&lt;td&gt;唯一标识码&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串，用时间生成一个 md5 码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;datetime&lt;/td&gt;
					&lt;td&gt;消息时间&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串，&lt;code&gt;yyyy-MM-dd HH:mm:ss&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;fileNames&lt;/td&gt;
					&lt;td&gt;文件名&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串，支持多个文件，以;为间隔&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;absoluteDataName&lt;/td&gt;
					&lt;td&gt;带路径的文件名&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;字符串，以;为间隔&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;fileSizes&lt;/td&gt;
					&lt;td&gt;文件大小（单位：byte）&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字符串，以;为间隔&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;result&lt;/td&gt;
					&lt;td&gt;处理状态&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;Int 型，正确（0）、错误（-1）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;resultDesc&lt;/td&gt;
					&lt;td&gt;处理状态描述&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;字符串，正确则描述处理的内容；错误描述具体错误内容&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;reserved&lt;/td&gt;
					&lt;td&gt;扩展&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;字符串&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于数值预报产品来说，我们一般只更关心某个时次某个时效的产品在何时生成。
尽管产品唯一标识码 &lt;code&gt;PID&lt;/code&gt;，文件名 &lt;code&gt;fileName&lt;/code&gt;、&lt;code&gt;absoluteDataName&lt;/code&gt; 中都可以体现产品的起报时间和预报时效，但不够直观，所以在设计数值预报产品消息时，使用了自定义的 &lt;code&gt;resultDesc&lt;/code&gt; 段。&lt;/p&gt;</description></item><item><title>NWPC消息平台：标准时间统计算法</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-23-nwpc-message-calculate-standard-time/</link><pubDate>Wed, 30 Dec 2020 15:34:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-23-nwpc-message-calculate-standard-time/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;数值天气预报是基于数学物理方法客观定量计算未来天气演变的科学，是一个跨学科的复杂而严格的系统性工程 [1]。
数值天气预报业务系统通常由多个步骤构成，一般分为资料前处理、模式计算和产品后处理等三个步骤 [2]。
面向用户的最终产品由产品后处理步骤生成，产品生成的时效受前面步骤的影响。&lt;/p&gt;
&lt;p&gt;NWPC 数值预报业务系统的前处理步骤需要从多种来源获取观测数据，包括 HPC 共享存储、CIMISS、FTP 等，并对这些资料进行处理，转为模式系统可以识别的输入数据。
受 HPC 文件系统 I/O 速度、网络传输速率、数据接口响应时间等因素影响，每个时次的资料前处理步骤运行时长会有一定的浮动。
模式同化和模式积分等计算任务需要使用大量计算节点，不同时次模式计算步骤的运行时长有一定的浮动。
产品后处理涉及大量文件系统 I/O 操作，运行时间也会有一定的浮动。
综上所述，数值预报业务系统各个时次的运行时间段常常不够稳定，模式产品的生成时间通常会在一定的区间范围内浮动。
所以，需要一种有效的方法计算模式产品的标准生成时间段。&lt;/p&gt;
&lt;p&gt;本文介绍 NWPC 消息平台目前使用的一种计算标准时间段的方法。&lt;/p&gt;
&lt;h2 id="资料"&gt;资料&lt;/h2&gt;
&lt;p&gt;使用 NWPC 消息平台产品事件消息类型中的原始分辨率 GRIB 2 产品完成上传二级存储的消息作为产品生成的时间数据。
统计 GRAPES GFS、GRAPES MESO 10KM、GRAPES MESO 3KM 和 GRAPES TYM 四个模式所有时次的产品生成标准时间段。&lt;/p&gt;
&lt;p&gt;GRAPES GFS 模式 10 月 3 日 06 时次 120 小时 GRIB 2 产品生成的事件消息数据如下所示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;nwpc-message-client&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2020-10-03T10:47:20.395949667Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;storage&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;forecast_time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;120h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;start_time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2020-10-03T06:00:00Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;stream&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;oper&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;system&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;grib2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;产品生成消息的详细介绍请参看文章《&lt;a href="https://blog.perillaroc.wang/post/2020/10/2020-10-01-nwpc-message-production-message/"&gt;NWPC消息平台：产品事件消息&lt;/a&gt;》。&lt;/p&gt;</description></item><item><title>R语言实战：基本数据管理</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-28-r-in-action-chap04-basic-data-operation/</link><pubDate>Mon, 28 Dec 2020 21:44:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-28-r-in-action-chap04-basic-data-operation/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;构造 &lt;code&gt;data.frame&lt;/code&gt; 对象&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;manager &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;10/24/08&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;10/28/08&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;10/1/08&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;10/12/08&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;5/1/09&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;country &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;US&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;US&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UK&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UK&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UK&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gender &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;M&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;M&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;age &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;39&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;99&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;q1 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;q2 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;q3 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;q4 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NA&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;q5 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NA&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;leadership &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data.frame&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; manager,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; country,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gender,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; age,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; q1,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; q2,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; q3,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; q4,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; q5,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stringsAsFactors&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;leadership
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; manager date country gender age q1 q2 q3 q4 q5
1 1 10/24/08 US M 32 5 4 5 5 5
2 2 10/28/08 US F 45 3 5 2 5 5
3 3 10/1/08 UK F 25 3 5 5 5 2
4 4 10/12/08 UK M 39 3 3 4 NA NA
5 5 5/1/09 UK F 99 2 2 1 2 1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;每一列表示一个变量，每一行表示一个观测&lt;/p&gt;</description></item><item><title>NWPC消息平台：消息代理服务</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-17-nwpc-message-broker-for-ecflow-command-message/</link><pubDate>Wed, 23 Dec 2020 09:41:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-17-nwpc-message-broker-for-ecflow-command-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;CMA 目前使用的高性能计算机系统 CMA-PI 由三种节点组成：计算节点、前后处理节点和管理登录节点。&lt;/p&gt;
&lt;p&gt;CMA-PI 内部使用高速计算网络连接，与外界网络隔离，仅有前后处理节点和管理登录节点与 CMA 局域网相连。&lt;/p&gt;
&lt;p&gt;详情请查看去年为单位培训准备的材料《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-09-03-nwpc-hpc-tutorial-hpc-introduction/"&gt;NWPC高性能计算机环境介绍：高性能计算机概况&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;计算节点属于 CMA-PI 作业调度系统 Slurm 中的并行队列 (operation, normal, largemem, &amp;hellip;)，前后处理节点属于串行队列 (serial_op, serial, &amp;hellip;)。
数值预报业务系统的 ecFlow 服务程序运行在管理登录节点上 (login_b01 和 login_b06)，大部分任务会被提交到调度系统的并行队列和串行队列。
NWPC 消息平台使用的消息中间件运行在与 CMA 局域网相连的气象大数据平台中，无法与 CMA-PI 的高速计算网络进行通讯。
所以，需要有效的方式解决并行作业与消息中间件的通讯问题。&lt;/p&gt;
&lt;p&gt;本文设计并实现一种消息代理服务，通过转发消息解决 CMA-PI 并行计算节点与 CMA 局域网无法通讯的问题。&lt;/p&gt;
&lt;h2 id="设计"&gt;设计&lt;/h2&gt;
&lt;p&gt;因为管理登录节点同时与 HPC 高速计算网络和 CMA 局域网连接，本文在 HPC 的管理登录节点上运行后台服务程序，提供消息代理转发服务。
该服务接收从 HPC 计算节点通过高速计算网络发送的事件消息，并通过 CMA 局域网转发给消息中间件。&lt;/p&gt;
&lt;h3 id="架构设计"&gt;架构设计&lt;/h3&gt;
&lt;p&gt;消息代理服务的数据流如下图所示。
代理服务运行在 CMA-PI 的登录节点上，并在高速计算网络上开放端口用于接收消息。
计算节点上运行的作业脚本调用消息发送客户端程序，通过端口向代理服务发送消息，代理服务接收消息后会通过 CMA 局域网将消息转发给消息队列。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/broker/nwpc-message-broker.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;消息代理服务数据流图，代理服务部署在 HPC 登录节点中&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="接口设计"&gt;接口设计&lt;/h3&gt;
&lt;p&gt;消息代理服务的数据接口由两部分组成：事件消息以及消息中间件的连接信息。
本文为不同的消息中间件开发不同的数据接口，每种数据接口都包含相同格式的表示事件消息的字节流字段 (Message)，并针对不同中间件的需求定义不同的连接目标字段 (Target)。
目前已为 RabbitMQ 和 Kafka 开发数据接口，如下图所示，其中 Kafka 接口支持多个 Broker 地址。&lt;/p&gt;</description></item><item><title>NWPC消息平台：发送ecFlow命令消息</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-11-nwpc-message-send-ecflow-message/</link><pubDate>Wed, 16 Dec 2020 16:44:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-11-nwpc-message-send-ecflow-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;ecFlow 中运行的任务脚本通过 &lt;code&gt;ecflow_client&lt;/code&gt; 命令与 ecFlow 服务进行通讯，告知服务任务运行状态的变化。
每次命令调用都会在 ecFlow 服务的日志文件中写入一条记录。&lt;/p&gt;
&lt;p&gt;详情请参看文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-18-ecflow-notebook-parse-child-command-log/"&gt;ecFlow笔记：ecFlow日志解析 - child 命令记录&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;此类数据可以作为任务运行状态变化的数据，从这些数据组成的序列中可以计算得到某个任务的运行情况。&lt;/p&gt;
&lt;p&gt;一个直观的想法就是监控 ecFlow 日志文件，实时获取业务系统的运行状态。
但笔者之前测试发现，无法保证日志信息会实时写入到文件中。
尤其在添加监听程序后，可以观察到部分日志的写入延迟会显著增加。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：从今天的临时测试 (&lt;code&gt;tail -f&lt;/code&gt;) 看，可以进行实时更新，上述结论存疑，需要进一步验证。&lt;/p&gt;
&lt;p&gt;不过，仍有理由使用额外的机制保存业务系统日志信息，比如不应该将业务监控紧密绑定在 ecFlow 上。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWPC 消息平台对任务脚本使用的 &lt;code&gt;ecFlow_client&lt;/code&gt; 命令进行封装，向消息平台发送 ecFlow 命令消息，作为任务运行状态变化的数据。
后端应用可以从消息队列中获取该数据，从而对业务系统的运行状况进行实时监控。&lt;/p&gt;
&lt;p&gt;本文介绍如何封装 &lt;code&gt;ecflow_client&lt;/code&gt; 命令实现发送 &lt;strong&gt;ecFlow 命令消息&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="设计"&gt;设计&lt;/h2&gt;
&lt;p&gt;本文对 &lt;code&gt;ecflow_clinet&lt;/code&gt; 命令的封装需要满足以下原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不影响任务正常运行，包括与 ecFlow 服务的通讯&lt;/li&gt;
&lt;li&gt;对现有业务流程影响最小，仅需要少量修改即可启用或关闭&lt;/li&gt;
&lt;li&gt;以附加组件的形式存在，各个系统间互不影响&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;根据以上原则，本文设计封装 &lt;code&gt;ecflow_clinet&lt;/code&gt; 发送 ecFlow 命令消息的方案，如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/send/ecflow/send-message.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;封装 ecflow_client 命令发送 ecFlow 命令消息示意图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;核心思想是通过配置环境变量 &lt;code&gt;PATH&lt;/code&gt;，将任务脚本中的 &lt;code&gt;ecflow_client&lt;/code&gt; 路径指向封装后的工具脚本，在该工具脚本中调用实际 &lt;code&gt;ecflow_client&lt;/code&gt; 命令，并额外向 NWPC 消息平台发送消息。
业务系统仅需在所有任务都会加载的头文件 (例如 &lt;code&gt;head.h&lt;/code&gt;) 中调用修改环境变量的集成脚本，即可启用或关闭消息发送功能，无需修改其他脚本。&lt;/p&gt;</description></item><item><title>年度工作汇报后的感想</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-15-thoughts-after-section-summay/</link><pubDate>Tue, 15 Dec 2020 23:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-15-thoughts-after-section-summay/</guid><description>&lt;p&gt;今天室里进行了年终总结，我在下午也汇报了今年的工作。
因为我们科是最后一组进行汇报，所以我也能完整地听了所有同事的报告，颇有感触。&lt;/p&gt;
&lt;p&gt;最重要的事情需要说三遍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;论文！论文！论文！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;看到大家的各项工作不是已发表论文，就是在总结成论文的路上，感觉自己的工作都白干了，也深刻意识到忽视论文写作是一个完全错误的选择。
尤其是最近两年耗费太多时间在写代码以及很多没有实际产出的任务上，白白浪费了时间。
好在这次总结给我敲响了警钟，我该好好反思下这一年来的工作是否已偏离正确的轨道，思考下明年应该如何安排各项工作，是否应该将撰写论文作为最核心的工作目标。&lt;/p&gt;
&lt;p&gt;这就涉及到对工作思维的调整。
多年的运维工作给我带来非常深刻的影响。
虽然不是每天都在进行运维值班，但保障业务稳定运行的责任早已化为隐形的鞭策，贯穿于工作和生活之中。&lt;/p&gt;
&lt;p&gt;从没想到我们单位的工作还会与职业健康问题相关，但这次汇报中同事已有提及。
而我也完全认为对于运维岗位来说，职业健康问题已成为不可忽视的一部分。
随着年龄的增长，夜间处理故障会对身体造成越来越大的伤害。
如果在身体和工作之间需要有所权衡，虽然不知道几年之前的我会如何选择，但现在的我会毫不犹豫地就选择身体健康，而在工作中付出相应的代价作为交换。&lt;/p&gt;
&lt;p&gt;职业健康不仅涉及身体，还与心理有关。
运维工作带来的无形压力已无法被我强行忽视。
即便运维的现状暂时无法改变，我也可以尝试调整自己的心态，不要局限在运维工作中，将工作重心放到科研工作中。
虽然我不是气象专业出身，但数据处理之类的前后端任务还是不需要太多专业背景的。
实在不行，不是也可以研究下工作流相关工具么。&lt;/p&gt;
&lt;p&gt;写写论文，总比天天看着监控界面有意思多了。&lt;/p&gt;</description></item><item><title>R语言实战：图形初阶</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-15-r-in-action-chap03-plot/</link><pubDate>Tue, 15 Dec 2020 23:10:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-15-r-in-action-chap03-plot/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言实战》(R in Action, 2nd)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="使用图形"&gt;使用图形&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;attach&lt;/span&gt;(mtcars)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(wt, mpg)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;abline&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(mpg &lt;span style="color:#f92672"&gt;~&lt;/span&gt; wt))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;title&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Regression of MPG on Weight&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;detach&lt;/span&gt;(mtcars)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/ria/chap03/mpg-wt.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="简单示例"&gt;简单示例&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dose &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drugA &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;drugB &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;31&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(dose, drugA, type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/ria/chap03/simple-plot.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="图形参数"&gt;图形参数&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;par()&lt;/code&gt; 函数设置绘图样式&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;opar &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;par&lt;/span&gt;(no.readonly&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;par&lt;/span&gt;(lty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, pch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(dose, drugA, type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;par&lt;/span&gt;(opar)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/ria/chap03/par-01.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;某些参数可以直接在绘图函数中设置&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(dose, drugA, type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, lty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, pch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;17&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/ria/chap03/par-02.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="符号和线条"&gt;符号和线条&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pch&lt;/code&gt;：点符号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lty&lt;/code&gt;：线条类型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cex&lt;/code&gt;：符号大小&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lwd&lt;/code&gt;：线条宽度&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dose, drugA,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lwd&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pch&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cex&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/ria/chap03/mark.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="颜色"&gt;颜色&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;col&lt;/code&gt;：默认颜色&lt;/li&gt;
&lt;li&gt;&lt;code&gt;col.axis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;col.lab&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;col.main&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;col.sum&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fg&lt;/code&gt;：前景色&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bg&lt;/code&gt;：背景色&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;颜色值可以是：&lt;/p&gt;</description></item><item><title>2020年工作总结</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-06-2020-summary-of-working-at-nwpc/</link><pubDate>Mon, 07 Dec 2020 16:23:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-06-2020-summary-of-working-at-nwpc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是为下周二 (12月15日) 年度工作汇报准备的 PPT，后续可能会有改动&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大家好，下面我汇报下 2020 年的工作。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/work/slide-01.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我的汇报主要包含六个部分。&lt;/p&gt;
&lt;h2 id="数据处理技术"&gt;数据处理技术&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/work/slide-02.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;首先介绍数据处理技术，今年研究数据处理技术的主要目标有两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供方便使用的数据访问工具&lt;/li&gt;
&lt;li&gt;研究分布式数据处理技术&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="数据访问工具库"&gt;数据访问工具库&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/work/slide-03.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;https://github.com/nwpc-oper/nwpc-data&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今年为 GRAPES 系列模式开发 GRIB 2 数据访问 Python 工具库 nwpc-data，提供查找数据文件和检索要素场的便捷方法，属于 GetPy 软件包的一部分。&lt;/p&gt;
&lt;p&gt;左边是数据文件路径查找的代码，支持 HPC 和二级存储。&lt;/p&gt;
&lt;p&gt;右边是加载 GRIB2 要素场的代码，基于 eccodes-python 库实现。&lt;/p&gt;
&lt;h3 id="分布式数据处理技术"&gt;分布式数据处理技术&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/work/slide-04.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;为了提高数据处理效率，今年我研究了一种实现分布式数据处理的方法。&lt;/p&gt;
&lt;p&gt;该方法将计算表示成 &lt;strong&gt;有向无环图&lt;/strong&gt;，在一组&lt;strong&gt;计算单元&lt;/strong&gt;中按&lt;strong&gt;依赖关系&lt;/strong&gt;完成整张图的计算。
目前我使用 Dask 库实现并行计算功能。&lt;/p&gt;
&lt;p&gt;我使用该方法进行了三项试验&lt;/p&gt;
&lt;h4 id="试验-1批量绘图"&gt;试验 1：批量绘图&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/work/slide-05.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-graphics"&gt;https://github.com/nwpc-oper/nwpc-graphics&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;首先使用该方法实现批量图片绘制。&lt;/p&gt;
&lt;p&gt;这是一种最简单的分布式数据处理过程，所有任务之间没有依赖关系。&lt;/p&gt;
&lt;p&gt;使用分布式数据处理技术，可以将 NCL 脚本批量绘制 400 张图片的时间从串行的 50 分钟减少到 5 分钟以内，将运行时间减少一个数量级。&lt;/p&gt;
&lt;p&gt;右图展示了该方法的扩展性能，可以看到，增加 CPU 核心数可以有效缩短批量绘图的时间。&lt;/p&gt;
&lt;h4 id="试验2提取站点数据"&gt;试验2：提取站点数据&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/summary/work/slide-06.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/perillaroc/nwpc-data-tool"&gt;https://github.com/perillaroc/nwpc-data-tool&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一个更复杂的例子是从多时效文件中提取站点数据，包括站点垂直廓线数据和经向、纬向剖面数据。
在这个试验中，需要从 25 个文件中总共提取 3750 个要素场。&lt;/p&gt;</description></item><item><title>《R语言编程艺术》读书笔记</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-05-the-art-of-r-programming-notebook/</link><pubDate>Sat, 05 Dec 2020 21:11:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-05-the-art-of-r-programming-notebook/</guid><description>&lt;p&gt;《R 语言编程艺术》(The Art of R Programming: A Tour of Statistical Software Design) 是我的第一本 R 语言入门书。&lt;/p&gt;
&lt;p&gt;秉承一年学习一门新编程语言的目标，今年下半年终于选定将 R 语言作为继 GO 语言后的下一个目标。
虽然 R 语言更多用于统计学，但在气象领域中也有诸多应用。
R 语言也是 CMA-PI 编程语言家族中的一员。&lt;/p&gt;
&lt;p&gt;开始学习前，我在知乎上看到一篇回答，介绍基本 R 语言的入门书籍，其中提到《R 语言编程艺术》更适合从程序员的角度学习 R 语言。&lt;/p&gt;
&lt;p&gt;从我最近三个月的阅读来看，这本书确实适合想要快速了解 R 语言的程序员。
尽管本书成书于 10 年前，部分内容已不适用最新版本，并且翻译文本略显粗糙，但编程语言的基本元素没有显著的变化，仍可以拿来作为快速入门的教程。&lt;/p&gt;
&lt;h2 id="章节笔记"&gt;章节笔记&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-08-study-r-quickstart/"&gt;快速入门&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-13-study-r-vector/"&gt;向量&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-16-study-r-matrix-and-array/"&gt;矩阵和数组&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-23-study-r-list/"&gt;列表&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-27-study-r-data-frame/"&gt;数据框&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-28-study-r-factor-and-table/"&gt;因子和表&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/10/2020-10-18-study-r-programming/"&gt;编程结构&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/10/2020-10-26-study-r-math/"&gt;数学运算与模拟&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-01-study-r-oop/"&gt;面向对象编程&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-07-study-r-io/"&gt;输入与输出&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-12-study-r-string/"&gt;字符串操作&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-14-study-r-plot/"&gt;基础绘图&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-19-study-r-speed/"&gt;性能提升——速度和内存&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-22-study-r-interface/"&gt;R与其他语言的接口&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/11/2020-11-25-study-r-parallel/"&gt;简单并行计算&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="环境"&gt;环境&lt;/h2&gt;
&lt;p&gt;前几个章节使用 Jupyter Notebook + R kernal，后面发现 RStudio 更适合在桌面电脑上使用，所以后期转为使用 RStudio + R Markdown。&lt;/p&gt;
&lt;p&gt;但 RStudio 在 Linux 服务器上尤其是没有管理员权限的 HPC 上不方便使用，所以后续学习中如果涉及 HPC 上的气象数据，可能仍然会使用 Jupyter Notebook。&lt;/p&gt;</description></item><item><title>面对工作要更轻松些</title><link>https://blog.perillaroc.wang/post/2020/12/2020-12-04-facing-devops-work-easily/</link><pubDate>Fri, 04 Dec 2020 23:43:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/12/2020-12-04-facing-devops-work-easily/</guid><description>&lt;p&gt;最近一周时间都在准备年终总结，今天终于跑完最后一组实验，也就完成了总结中的最后一项新增内容。
今年的工作也就只剩下周四的年度工作汇报了。下面一周我不会大幅度修改 PPT，也不会为完成新的工作目标而加班加点。
年底的时候总要给自己放松一些。&lt;/p&gt;
&lt;p&gt;虽然我觉得自己准备总结的时间很充裕，但我可能还是在内心深处对工作总结有些焦虑，连晚上都在运行程序、等待结果和赶制 PPT。
整个人全天都处在同一个频道中，不是一种很理想的状态。&lt;/p&gt;
&lt;p&gt;不知道最近几天身体不适是不是就和做 PPT 有关。
不过，更大程度上应该是来自作息时间的不规律和对运动的不重视。
这种对身体不负责的态度不仅会害了自己，也会害了家人。
今天下午女儿发烧吓了我一身冷汗，好在吃了退烧药后体温已恢复正常。
我不禁在问自己：是不是我传染的？为什么这么不注重身体？&lt;/p&gt;
&lt;p&gt;昨天夜里 3 点起来处理业务系统故障直到 5 点，最终还是靠联系同事才成功解决。
我又想起之前偶尔想起却刻意被我忽视的问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;五年、十年之后，是否还从事业务系统的运维工作？
是否还会在深夜里被叫醒处理千奇百怪的故障？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对于这个问题我没有乐观的答案。&lt;/p&gt;
&lt;p&gt;三四年前，我曾经以为通过开发一系列工具会极大减轻运维的压力。
但现在我已不再抱有这种不现实的幻想，单靠一个人想改变现状是远远不够的。
而且诸如观测资料和 HPC 性能等很多外界因素并不是一个单位一个科室可以解决的。
所以，还不如将精力投入到其它方面。&lt;/p&gt;
&lt;p&gt;最近单位终于着手引入外部力量参与运维，如果成功则有望缓解近几年运维力量持续衰减的趋势。
不过与公司的交流让我有一丝不妙的感觉。
项目经理说公司的运维团队都是年轻人，而我在运维团队负责人面色上似乎看到熬夜比较容易出现的一些症状。
即便再年轻，身体也扛不住长久的夜班生活。
另外项目经理提到 NMIC 运维白天由女同志负责，夜间由男同志负责。
虽然无论是公司，NMIC，还是我们，值班都是由多人轮值，但毕竟还是会碰到夜里需要处理的故障，值班期间也要背负及时处理故障的责任和压力。
更重要的一点在于，类似的值班工作完全看不到胜利的彼岸。
无论是五年还是十年，只要还在这个岗位，就得从事同样的值班工作。
所以，我也只能刻意回避上面的问题，因为面对这样的现状，我也不愿意明确地回答自己。&lt;/p&gt;
&lt;p&gt;穷则思变。无论是在局长 2020 年全国气象局长工作研讨会上的总结讲话，还是科技与气候变化司2020年度全面深化气象改革工作总结中，都有迹象表明坊间传闻明年单位将会迎来重大变动已成定局。
虽然同事觉得即便单位有变动，也不会给我们部门带来太大的影响，职责不变，该做什么还得做什么。
但我还是觉得，能不做运维还是不要做了。
尤其在以科研为核心的单位中，运维岗位不会优先配备力量。不会像预报员岗位一样，有源源不断的新鲜力量加入。
我去年就已经提过，太重视科研会导致整个团队对业务工作的忽视，从而将所有业务压力完全传导给处在最末端的运维人员。
业务工作只有处理不完的故障。所以，还是得向科研靠拢。&lt;/p&gt;
&lt;p&gt;虽然我没有从事过科研工作，但我还是觉得科研与业务运维完全不同。
业务系统每天运行，将产品是否按时生成作为硬性考核指标，没按时生成就是事故，无论故障原因如何，运维都很难摆脱责任，而没有人关注运行正常的时候。
科研则不太一样，有更多的弹性，即便没有突破性成果，还是可以说一直在进行科学研究，一旦形成成果，就能带来巨大的收益。
即使没有科研成果，原地踏步，也不会有从事运维工作迟早会碰到的“天降大锅”，所以科研工作它难道不香么？&lt;/p&gt;
&lt;p&gt;多年运维会养成一种时刻向前冲的习惯，会带来许多不必要的压力。
是时候该好好考虑一番了。即便暂时无法改变现状，但总可以用更轻松的心态面对工作。
慢慢走路，才能更好地欣赏路边的风景。&lt;/p&gt;
&lt;p&gt;写了这么多废话，也该去睡觉了。早睡早起，身体健康。&lt;/p&gt;</description></item><item><title>学习R语言：简单并行计算</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-25-study-r-parallel/</link><pubDate>Wed, 25 Nov 2020 21:22:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-25-study-r-parallel/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不要对并行抱有太高期望，很多情况下并行版本实际上比串行版本运行速度更慢。&lt;/p&gt;
&lt;h2 id="共同外链问题"&gt;共同外链问题&lt;/h2&gt;
&lt;p&gt;mutual outlink&lt;/p&gt;
&lt;p&gt;对于 n x n 矩阵&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sum = 0
for i = 0...n-1
 for j = i+1...n-1
 for k = 0...n-1 sum = sum + a[i][k] * a[j][k]
mean = sum / (n*(n-1)/2)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="snow-包简介"&gt;snow 包简介&lt;/h2&gt;
&lt;h3 id="定义问题"&gt;定义问题&lt;/h3&gt;
&lt;p&gt;上述问题的源代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mtl &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(ichunk, m) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ncol&lt;/span&gt;(m)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; matches &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ichunk) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; n) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rowi &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; m[i,]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; matches &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; matches &lt;span style="color:#f92672"&gt;+&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;(m&lt;span style="color:#a6e22e"&gt;[&lt;/span&gt;(i&lt;span style="color:#ae81ff"&gt;+1&lt;/span&gt;)&lt;span style="color:#f92672"&gt;:&lt;/span&gt;n,] &lt;span style="color:#f92672"&gt;%*%&lt;/span&gt; rowi)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (matches)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mutlinks &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(cls, m) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; n &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nrow&lt;/span&gt;(m)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nc &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(cls)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ichunks &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;split&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;n, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;nc)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; counts &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clusterApply&lt;/span&gt;(cls, ichunks, mtl, m)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;do.call&lt;/span&gt;(sum, counts) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; (n&lt;span style="color:#f92672"&gt;*&lt;/span&gt;(n&lt;span style="color:#ae81ff"&gt;-1&lt;/span&gt;)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;split()&lt;/code&gt; 函数用于将矩阵分块&lt;/p&gt;</description></item><item><title>论文阅读：适用于地球系统模式工作流的轻量并行Python工具</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-23-paper-paul-2015-parallel-python-tools-for-esm-workflows/</link><pubDate>Mon, 23 Nov 2020 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-23-paper-paul-2015-parallel-python-tools-for-esm-workflows/</guid><description>&lt;blockquote&gt;
&lt;p&gt;K. Paul, S. Mickelson, J. M. Dennis, H. Xu and D. Brown, &amp;ldquo;Light-weight parallel Python tools for earth system modeling workflows,&amp;rdquo; 2015 IEEE International Conference on Big Data (Big Data), Santa Clara, CA, 2015, pp. 1985-1994, doi: 10.1109/BigData.2015.7363979.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;论文介绍用于制作 CMIP 6 数据集的两个轻量化并行 Python 工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/NCAR/PyReshaper"&gt;PyReshaper&lt;/a&gt;：将多个时间片 (time-slice) 数据转换为时间序列 (time-series) 数据&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/NCAR/pyAverager"&gt;PyAverager&lt;/a&gt;：计算时间序列数据的统计值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，本文开发工具的指导思想也值得借鉴。&lt;/p&gt;
&lt;h2 id="论文"&gt;论文&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;以下内容摘选自论文，并附加笔者个人理解，如有偏差，敬请谅解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="介绍"&gt;介绍&lt;/h3&gt;
&lt;p&gt;生成 CESM 模式的 CMIP 6 数据集需要处理 12 PB 的原始输出。
之前使用的串行处理工具无法处理如此庞大的数据，论文开发轻量级并行 Python 工具替换现有方案中的瓶颈软件 (bottleneck software)。&lt;/p&gt;
&lt;p&gt;论文仅关注地球系统模式中的一个方面，即数据密集型问题。&lt;/p&gt;
&lt;p&gt;本文涉及三类文件&lt;/p&gt;</description></item><item><title>学习R语言：R与其他语言的接口</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-22-study-r-interface/</link><pubDate>Sun, 22 Nov 2020 22:54:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-22-study-r-interface/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍在 R 语言中调用 C/C++ 和在 Python 中调用 R。&lt;/p&gt;
&lt;h2 id="编写能被-r-调用的-cc-函数"&gt;编写能被 R 调用的 C/C++ 函数&lt;/h2&gt;
&lt;p&gt;通过 &lt;code&gt;.C()&lt;/code&gt; 和 &lt;code&gt;.Call()&lt;/code&gt; 实现&lt;/p&gt;
&lt;h3 id="r-与-cc-交互的预备知识"&gt;R 与 C/C++ 交互的预备知识&lt;/h3&gt;
&lt;p&gt;C 语言中二维数组按行存储，R 语言中按列存储&lt;/p&gt;
&lt;p&gt;C 语言中下标从 0 开始，R 语言中从 1 开始&lt;/p&gt;
&lt;p&gt;R 传递给 C 的参数都是以指针形式存在的，C 语言函数的返回值必须是 &lt;code&gt;void&lt;/code&gt;。
从 C 函数返回值必须通过函数的参数。&lt;/p&gt;
&lt;h3 id="示例提取方阵的次对角线元素"&gt;示例：提取方阵的次对角线元素&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;R.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;subdiag&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;double&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;m,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;n,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;k,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;double&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;result
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; nval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;n;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; kval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;k;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; stride &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nval &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, j &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kval; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; nval &lt;span style="color:#f92672"&gt;-&lt;/span&gt; kval; &lt;span style="color:#f92672"&gt;++&lt;/span&gt;i, j&lt;span style="color:#f92672"&gt;+=&lt;/span&gt;stride) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result[i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; m[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行命令&lt;/p&gt;</description></item><item><title>学习R语言：性能提升——速度和内存</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-19-study-r-speed/</link><pubDate>Thu, 19 Nov 2020 22:23:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-19-study-r-speed/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;时间和空间的权衡&lt;/p&gt;
&lt;h2 id="编写快速-r-代码"&gt;编写快速 R 代码&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;向量化，字节码编译，其他方法&lt;/li&gt;
&lt;li&gt;核心部分用编译型语言编写，如 C/C++（后续文章介绍）&lt;/li&gt;
&lt;li&gt;并行（后续文章介绍）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="可怕的-for-循环"&gt;可怕的 &lt;code&gt;for&lt;/code&gt; 循环&lt;/h2&gt;
&lt;h3 id="用向量化提升速度"&gt;用向量化提升速度&lt;/h3&gt;
&lt;h4 id="示例1"&gt;示例1&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;runif&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10000000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;runif&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10000000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vector&lt;/span&gt;(length&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10000000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;向量化版本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;system.time&lt;/span&gt;(z &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; user system elapsed 
 0.01 0.01 0.03 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;for&lt;/code&gt; 循环&lt;/p&gt;
&lt;p&gt;注意：R 中每个操作都是函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;system.time&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(x)) z[i] &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; x[i] &lt;span style="color:#f92672"&gt;+&lt;/span&gt; y[i])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; user system elapsed 
 0.84 0.00 0.85 
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="示例2"&gt;示例2&lt;/h4&gt;
&lt;p&gt;向量过滤？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oddcount &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(x) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sum&lt;/span&gt;(x&lt;span style="color:#f92672"&gt;%%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sample&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10000000&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10000000&lt;/span&gt;, replace&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;向量化版本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;system.time&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;oddcount&lt;/span&gt;(x))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; user system elapsed 
 0.22 0.00 0.22 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;for&lt;/code&gt; 版本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;system.time&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(x)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (x[1]&lt;span style="color:#f92672"&gt;%%&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) c &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; c &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; user system elapsed 
 2.13 0.00 2.13 
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="向量化函数举例"&gt;向量化函数举例&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ifelse()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;which()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;where()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;any()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;all()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cumsum()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cumprod()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rowSums()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;colSums()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;combn()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;outer()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lower.tri()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;upper.tri()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expand.grid()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="扩展案例在蒙特卡罗模拟中获得更快的速度"&gt;扩展案例：在蒙特卡罗模拟中获得更快的速度&lt;/h3&gt;
&lt;h4 id="示例1-1"&gt;示例1&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;for&lt;/code&gt; 循环&lt;/p&gt;</description></item><item><title>是时候该放松放松了</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-19-thoughts-before-annual-summary/</link><pubDate>Thu, 19 Nov 2020 22:12:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-19-thoughts-before-annual-summary/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文仅记录笔者写作当时的想法，角度过于偏颇，不代表笔者的想法未来不会改变。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最近一段时间总觉得有些不对劲，可是也说不清到底是因为什么。&lt;/p&gt;
&lt;p&gt;可能是年底疲于追赶项目经费执行进度，有些急躁。
但明明报销单已经提交，完成进度没有太大难度，应该不用再担心报销问题了。&lt;/p&gt;
&lt;p&gt;可能是今年进展不顺的专项课题年底需要提交总结材料，有些担心如何交差。
但明明总结材料已经汇总完毕，今年的工作也算有了一个着落，应该不需要再突击攻关了。&lt;/p&gt;
&lt;p&gt;可能是关注各单位正在进行的职称评审工作，发现明年自己评上的希望不大，有些焦虑。
但明明是我自己常年专注业务工作，爱写代码，不爱写论文，光焦虑能有什么用，焦虑又带不来文章。&lt;/p&gt;
&lt;p&gt;可能是关于单位前景的传言迟迟得不到确认，不知道未来自己会从事什么样的岗位，有些不知所措。
但即使传言落实，也与整个单位所有人相关，看着同事都在持续推进工作，我也不应该胡思乱想。&lt;/p&gt;
&lt;p&gt;想来想去，问题还是出在我自己身上：&lt;strong&gt;我一直缺乏作为科研工作者的觉悟&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;最近气象局一直在推行 &lt;strong&gt;研究型业务&lt;/strong&gt;，我觉得非常贴切。
单纯搞业务在领域内没有太大的发展空间，无法评职称，也无法获得各项荣誉。
毕竟业务工作门槛低，重复性强，同时因为对时效性要求较高，往往会占用大量精力。
一旦深陷其中，形成业务工作惯性，就很难再凝聚出研究型思维，无法从事研究工作。
所以一定要在做业务的同时开展研究工作。&lt;/p&gt;
&lt;p&gt;不过，业务工作的特点就是总量保持不变，如果不提高工作效率，总需要固定的人力去完成。
如果单位偏向于科研工作，那么剩下的业务工作只能由少数部门来承担。
业务方面很难做出有说服力拿得出手的成果，所以大家也许都偏向于进行科学研究，而尽量避免或者仅参与少量的业务工作。
当业务从业者看到自己从事的业务工作越来越集中，很难有进一步的发展空间，也许就会慢慢放弃在业务方面的追求。
这样很可能会导致单位的科研工作成果丰硕，但业务工作进展却非常缓慢。&lt;/p&gt;
&lt;p&gt;虽然我一直不愿承认我在沿着上述道路前行，但我也无法否认自己在业务系统建设及运维方面越来越失去钻研的动力。
看着监控界面上越来越多的业务系统，我再也无法像之前一样告诉自己：&lt;em&gt;只要开发各类工具提高工作效率，系统建设和运维就不会占用太多的精力&lt;/em&gt;。
我也逐渐能理解一些年轻时候想不明白的事情，也逐渐知道之前的某些想法实际上只是我自己太单纯没有看清现状罢了。&lt;/p&gt;
&lt;p&gt;又到了一年一度的年终总结阶段，我还是不要强行追赶进度，暂停新功能的开发，停止无意义的挣扎。&lt;/p&gt;
&lt;p&gt;是时候该好好回顾一下自己一年来的工作、学习和生活。
看看之前写的一些博文是否有需要完善丰富的地方。
想一想自己未来的发展方向，不要将全部精力都放到业务工作中，开始考虑将重心转移到研究科学问题上。
未来需要专注于科学问题，而不是业务系统运行是否正常。&lt;/p&gt;
&lt;p&gt;随着天气转凉，下班天色渐晚，已经很久没在工作日带女儿出去玩了，也该找找时间多陪陪女儿。
多看看书，多读读论文，学习些新知识，开阔下眼界，其他的事情就都放到一边吧，不要影响心情。&lt;/p&gt;
&lt;p&gt;是时候该放松放松了。&lt;/p&gt;</description></item><item><title>NWPC消息平台：在 ecFlow 系统中发送产品事件消息</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-15-send-production-messages-in-ecflow-system/</link><pubDate>Sun, 15 Nov 2020 20:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-15-send-production-messages-in-ecflow-system/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何在基于 ecFlow 构建的数值预报业务系统中发送 NWPC 消息平台的 &lt;strong&gt;产品事件消息&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;数值预报业务系统产品制作一般分为三个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;监视输出&lt;/strong&gt;：检测模式积分任务是否输出计算结果，使用单一任务循环检查文件是否存在，一般运行在 HPC 的登录节点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成产品&lt;/strong&gt;：根据模式输出结果制作产品，一般运行在 HPC 的串行和并行计算节点中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分发产品&lt;/strong&gt;：文件拷贝或 FTP 传输，需要与 HPC 外部通讯，一般运行在 HPC 的串行节点或登录节点&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/send/production/nwpc-post-system-flow.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;数值预报业务系统产品制作流程&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;NWPC 消息平台目前使用两种产品事件消息，对应于上述不同步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;面向 NMC 监控平台的表示 GRIB 2 产品已生成的消息，对应步骤 2&lt;/li&gt;
&lt;li&gt;面向 NWPC 消息系统的表示 GRIB 2 产品已上传到二级存储的消息，对应步骤 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数值预报业务系统根据事件消息的应用场景，使用不同方式发送以上两种产品事件消息。&lt;/p&gt;
&lt;h2 id="方案"&gt;方案&lt;/h2&gt;
&lt;p&gt;本节介绍将事件消息发送集成到数值预报业务系统中的两种方式。&lt;/p&gt;
&lt;h3 id="脚本集成"&gt;脚本集成&lt;/h3&gt;
&lt;p&gt;将事件消息发送命令加入到已有任务脚本中，是最简单的集成方式，无需对现有系统的结构进行修改。&lt;/p&gt;
&lt;p&gt;GRIB 2 产品生成消息目前使用这种方式。
该消息用于统计产品生成的时间，需要在产品生成后尽快发送。
最直观的方法就是将消息发送命令放到产品制作任务脚本的最后。
但实践中我们往往将产品生成与分发拆分为两个相关联的任务：产品制作任务只负责产品生成，不与系统外部进行交互；产品分发任务由产品制作任务驱动，与外部进行通讯。
产品制作任务可能运行在无法与外界进行通讯的计算节点上。
所以 NWPC 消息平台将产品生成消息发送命令放到分发任务脚本的开头，既符合将产品生成与分发相分离的要求，也能在第一时间发送消息，不受后续分发操作的影响。&lt;/p&gt;
&lt;p&gt;这种方式存在一定的弊端。&lt;/p&gt;
&lt;p&gt;(1) 如果产品分发任务执行失败并重新运行，对于同一个产品文件，会产生多条消息记录，需要后端应用对重复消息进行额外处理。&lt;/p&gt;
&lt;p&gt;(2) 业务系统为了保证分发任务执行稳定，会限制同时运行的任务数。分发任务可能会因作业数限制而延迟启动，影响产品生成消息按时发送。
另外，某些极端情况下，上传任务持续处于运行状态，后续任务无法运行，导致产品生成消息无法发送。&lt;/p&gt;
&lt;h3 id="消息发送任务"&gt;消息发送任务&lt;/h3&gt;
&lt;p&gt;为产品事件创建单独的发送任务可以解决消息重复发送的问题。&lt;/p&gt;
&lt;p&gt;GRIB 2 产品完成上传二级存储的消息目前使用这种方式。
该消息计划用于驱动部署在气象大数据云平台加工流水线上的产品制作任务，使后续系统无需重复监视二级存储中文件的到达情况。
产品上传任务一般运行在 HPC 的串行计算节点或其它专用传输节点上，受队列节点数限制。
而消息上传任务运行时间通常在 2 秒以内，资源消耗较少，所以可以直接在 ecFlow 服务运行节点（即 HPC 登录节点）上运行，不占用计算节点，不会因作业排队而带来额外的时间延迟。&lt;/p&gt;</description></item><item><title>学习R语言：基础绘图</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-14-study-r-plot/</link><pubDate>Sat, 14 Nov 2020 20:25:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-14-study-r-plot/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;介绍 R 基础绘图包的基本功能。&lt;/p&gt;
&lt;p&gt;注：R 语言更常用的绘图包是 ggplot2。笔者后续会进一步学习 ggplot2 的相关功能。&lt;/p&gt;
&lt;h2 id="创建图形"&gt;创建图形&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;plot()&lt;/code&gt; 函数&lt;/p&gt;
&lt;h3 id="基础图形系统的核心plot-函数"&gt;基础图形系统的核心：&lt;code&gt;plot()&lt;/code&gt; 函数&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;plot()&lt;/code&gt; 是泛型函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/study/plot/plot-vector.png"&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;plot()&lt;/code&gt; 函数分阶段执行。&lt;code&gt;type=&amp;quot;n&amp;quot;&lt;/code&gt; 表示不添加任何元素&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;-3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;-1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xlab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ylab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;y&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/study/plot/plot-panel.png"&gt;
&lt;/figure&gt;

&lt;h3 id="添加线条abline-函数"&gt;添加线条：&lt;code&gt;abline()&lt;/code&gt; 函数&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;abline()&lt;/code&gt; 使用截距和斜率绘制直线&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lmout &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;abline&lt;/span&gt;(lmout)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/study/plot/abline-lm.png"&gt;
&lt;/figure&gt;

&lt;p&gt;$$
y = 2 + 1 \cdot x
$$&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;plot&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;-3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;-1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; xlab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ylab&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;y&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;abline&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/study/plot/abline-vector.png"&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;lines()&lt;/code&gt; 函数&lt;/p&gt;</description></item><item><title>使用kafka-go连接Kafka</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-13-using-kafka-go-for-kafka/</link><pubDate>Fri, 13 Nov 2020 23:42:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-13-using-kafka-go-for-kafka/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何使用 &lt;a href="https://github.com/segmentio/kafka-go"&gt;kafka-go&lt;/a&gt; 库提供的高层 API 接口连接 Kafka。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;导入库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/segmentio/kafka-go&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="发送消息"&gt;发送消息&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;kafka.Writer&lt;/code&gt; 向 Kafka 服务器发送消息。&lt;/p&gt;
&lt;p&gt;创建 &lt;code&gt;Writer&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Writer&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Addr&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;TCP&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;brokers&lt;/span&gt;&lt;span style="color:#f92672"&gt;...&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Topic&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;topic&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Balancer&lt;/span&gt;: &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;LeastBytes&lt;/span&gt;{},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;WriteTimeout&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;writeTimeout&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brokers&lt;/code&gt; 是 Kafka 服务地址列表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;topic&lt;/code&gt; 是主题&lt;/li&gt;
&lt;li&gt;&lt;code&gt;writeTimeout&lt;/code&gt; 是超时时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发送消息，如果发送失败，&lt;code&gt;err&lt;/code&gt; 不为空&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteMessages&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Background&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Message&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;message&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;message&lt;/code&gt; 是消息字节流，类型是 &lt;code&gt;[]byte&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;消息发送完毕后，手动关闭 &lt;code&gt;Writer&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="接收消息"&gt;接收消息&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;kafka.Reader&lt;/code&gt; 从 Kafka 服务器接收消息。&lt;/p&gt;
&lt;p&gt;创建 &lt;code&gt;Reader&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewReader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ReaderConfig&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Brokers&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;brokers&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Topic&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;topic&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;GroupID&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;groupId&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;MinBytes&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10e3&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 10KB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;MaxBytes&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;10e6&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// 10MB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;groupId&lt;/code&gt; 是 consumer group 名称，每条消息只会向同一个 group 中某个 consumer 发送一次。&lt;/p&gt;</description></item><item><title>适用于NMC监控平台的数值预报产品消息</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-23-nwpc-production-message-for-nmc-monitor/</link><pubDate>Fri, 13 Nov 2020 21:51:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-23-nwpc-production-message-for-nmc-monitor/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NMC 建立了统一的业务监控平台，基于消息中间件 Kafka 实现消息系统，同时制定了统一的日志数据格式。&lt;/p&gt;
&lt;p&gt;本文介绍在该标准下设计的数值预报产品消息格式。&lt;/p&gt;
&lt;h2 id="日志消息格式"&gt;日志消息格式&lt;/h2&gt;
&lt;p&gt;日志消息格式参见《气象服务产品统一监控平台日志消息格式说明》。&lt;/p&gt;
&lt;p&gt;消息使用 JSON 格式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;datetime&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;fileName&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;absoluteDataName&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;desc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各个字段的说明如下表所示。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;字段名&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;可选&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;source&lt;/td&gt;
					&lt;td&gt;消息来源系统&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字典表1（省略）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;type&lt;/td&gt;
					&lt;td&gt;消息类型，用于区分不同功能&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字典表2（省略）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;datetime&lt;/td&gt;
					&lt;td&gt;操作时间&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;1970年1月1日后的毫秒数（北京时间）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;fileName&lt;/td&gt;
					&lt;td&gt;文件名&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;absoluteDataName&lt;/td&gt;
					&lt;td&gt;文件绝对路径&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;status&lt;/td&gt;
					&lt;td&gt;处理状态&lt;/td&gt;
					&lt;td&gt;必选&lt;/td&gt;
					&lt;td&gt;字典表3（省略）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;desc&lt;/td&gt;
					&lt;td&gt;自定义描述&lt;/td&gt;
					&lt;td&gt;可选&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于数值预报产品来说，我们一般只更关心某个时次某个时效的产品在何时生成。
尽管文件名&lt;code&gt;fileName&lt;/code&gt;中可以体现产品的起报时间和预报时效，但不够直观，所以在设计数值预报产品消息时，使用了自定义的 &lt;code&gt;desc&lt;/code&gt; 段。&lt;/p&gt;
&lt;h2 id="数值预报产品消息"&gt;数值预报产品消息&lt;/h2&gt;
&lt;p&gt;首先看一个实际发送的消息，表示 GRAPES GFS 系统 2020 年 3 月 23 日 00 时次的 021 时效 GRIB2 产品在 2020/3/23 12:27:02 生成。&lt;/p&gt;</description></item><item><title>学习R语言：字符串操作</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-12-study-r-string/</link><pubDate>Thu, 12 Nov 2020 22:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-12-study-r-string/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;尽管 R 是一门以数值向量和矩阵为核心的统计语言，但字符串同样极为重要。&lt;/p&gt;
&lt;h2 id="字符串操作函数概述"&gt;字符串操作函数概述&lt;/h2&gt;
&lt;h3 id="grep"&gt;&lt;code&gt;grep()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;grep(pattern, x)&lt;/code&gt; 在字符串向量 &lt;code&gt;x&lt;/code&gt; 中搜索给定字符串 &lt;code&gt;pattern&lt;/code&gt;，返回 &lt;code&gt;x&lt;/code&gt; 的索引&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;grep&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Pole&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Equator&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;North Pole&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;South Pole&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 2 3
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;grep&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pole&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Equator&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;North Pole&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;South Pole&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;integer(0)
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="nchar"&gt;&lt;code&gt;nchar()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;nchar()&lt;/code&gt; 函数返回字符串 &lt;code&gt;x&lt;/code&gt; 的长度&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nchar&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;South Pole&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 10
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nchar&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;NA&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] NA
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;nchar&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;integer(0)
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="paste"&gt;&lt;code&gt;paste()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;paste()&lt;/code&gt; 函数将若干个字符串拼接&lt;/p&gt;
&lt;p&gt;默认使用空格拼接&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;paste&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;North&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Pole&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;North Pole&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;sep&lt;/code&gt; 参数指定拼接字符&lt;/p&gt;</description></item><item><title>预测雷暴旋转的深度学习解释 - 数据</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-11-ams-ml-python-deep-learning-interpretation-data/</link><pubDate>Wed, 11 Nov 2020 22:14:35 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-11-ams-ml-python-deep-learning-interpretation-data/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Interpretation of deep learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_4/ML_Short_Course_Module_4_Interpretation.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_4/ML_Short_Course_Module_4_Interpretation.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本节着重于卷积神经网络 (convolutional neural networks, CNN) 的解释，这是一种深度学习模型，用于预测来自 NCAR (National Center for Atmospheric Research) convection-allowing ensemble 的数值模拟雷暴中的未来旋转 (Schwartz et al. 2015)。&lt;/p&gt;
&lt;p&gt;解释和理解模型在机器学习 (machine learning, ML) 的所有三个阶段都有好处：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;开发阶段&lt;/strong&gt;：可以用于调试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运行阶段&lt;/strong&gt;：可以增加用户对模型的信任和理解&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;机器学习阶段&lt;/strong&gt;：机器学习大大胜过人类的假想阶段可以用来提高人类的技能。对于国际象棋 (Johns &lt;em&gt;et al.&lt;/em&gt; 2015) 和围棋 (Silver &lt;em&gt;et al.&lt;/em&gt; 2016) 的游戏已经做到了这一点。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="参考文献"&gt;参考文献&lt;/h2&gt;
&lt;p&gt;本文引用了下面列出的一些出版物。&lt;/p&gt;
&lt;p&gt;Breiman, L., 2001: &amp;ldquo;Random forests.&amp;rdquo; &lt;em&gt;Machine Learning&lt;/em&gt;, &lt;strong&gt;45&lt;/strong&gt;, 5–32, &lt;a href="https://doi.org/10.1023/A:1010933404324"&gt;https://doi.org/10.1023/A:1010933404324&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>AMS机器学习课程：Keras深度学习 - 卷积神经网络正则化</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-07-ams-ml-python-keras-ann-regularization/</link><pubDate>Sat, 07 Nov 2020 17:31:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-07-ams-ml-python-keras-ann-regularization/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;David John Gagne, 2019: &amp;ldquo;Deep Learning with Keras&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_3/ML_Short_Course_Module_3_Deep_Learning.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_3/ML_Short_Course_Module_3_Deep_Learning.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;David John Gagne, National Center for Atmospheric Research&lt;/p&gt;
&lt;p&gt;本文接上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-25-ams-ml-python-keras-cnn/"&gt;AMS机器学习课程：Keras深度学习 - 卷积神经网络&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;由于要拟合大量的权重，并且要处理的数据量有限，如果神经网络受到不适当的约束，它们很容易过度拟合数据集中的噪声。
尽管使用卷积和池化确实可以充当正则化器，但对于具有许多权重的网络，可能需要其他正则化技术。&lt;/p&gt;
&lt;p&gt;我们将讨论两种常见的正则化技术：权重衰减 (Weight decay) 和丢弃法 (Dropout)。&lt;/p&gt;
&lt;h2 id="权重衰减"&gt;权重衰减&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/03/02/fig_lasso_ridge_1.png"&gt;
&lt;/figure&gt;

&lt;p&gt;权重衰减 (Weight decay) 是一种通过在损失函数中包含惩罚项来约束回归模型权重的方法，该函数将权重的总大小最小化。
惩罚项的影响由参数 alpha 控制。&lt;/p&gt;
&lt;p&gt;权重衰减有两种常见形式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ridge (或 L2 norm，Tikhonov)&lt;/li&gt;
&lt;li&gt;LASSO (或 L1 norm) 正则化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ridge 正则化将所有权重的大小减小一个恒定因子，但更相关的权重受到的影响较小，相关性较小的权重被最小化。&lt;/p&gt;
&lt;p&gt;LASSO 正则化将不太重要的权重减小为 0，从而导致权重稀疏。
LASSO 可以用作特征选择 (feature selection) 的一种形式。&lt;/p&gt;
&lt;p&gt;我们现在将使用权重的 Ridge 正则化训练 CNN。
这是通过在 Keras 中向每个 Conv2D 和 Dense 层添加 &lt;code&gt;kernel_regularizer=l2(l2_param)&lt;/code&gt; 参数来完成的。&lt;/p&gt;</description></item><item><title>学习R语言：输入与输出</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-07-study-r-io/</link><pubDate>Sat, 07 Nov 2020 15:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-07-study-r-io/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="连接键盘与显示器"&gt;连接键盘与显示器&lt;/h2&gt;
&lt;h3 id="scan"&gt;&lt;code&gt;scan()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;scan()&lt;/code&gt; 函数从文件中读取或者用键盘键入一个向量&lt;/p&gt;
&lt;p&gt;四个文件：&lt;/p&gt;
&lt;p&gt;z1.txt&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;123
4 5
6
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;z2.txt&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;123
4.2 5
6
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;z3.txt&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;abc
de f
g
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;z4.txt&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;abc
123 6
y
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scan&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/z1.txt&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Read 4 items
[1] 123 4 5 6
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scan&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/z2.txt&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Read 4 items
[1] 123.0 4.2 5.0 6.0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;读取 z3.txt 会出错，因为 &lt;code&gt;scan()&lt;/code&gt; 默认使用 double 模式读取。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scan&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/z3.txt&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Error in scan(&amp;#34;../data/z3.txt&amp;#34;) : scan() expected &amp;#39;a real&amp;#39;, got &amp;#39;abc&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用 &lt;code&gt;what&lt;/code&gt; 参数修改读取模式&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scan&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/z3.txt&amp;#34;&lt;/span&gt;, what&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Read 4 items
[1] &amp;#34;abc&amp;#34; &amp;#34;de&amp;#34; &amp;#34;f&amp;#34; &amp;#34;g&amp;#34; 
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;scan&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/z4.txt&amp;#34;&lt;/span&gt;, what&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Read 4 items
[1] &amp;#34;abc&amp;#34; &amp;#34;123&amp;#34; &amp;#34;6&amp;#34; &amp;#34;y&amp;#34; 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;scan()&lt;/code&gt; 默认情况下以空白字符 (whitespace) 作为分隔。
可以使用 &lt;code&gt;sep&lt;/code&gt; 参数手动设置&lt;/p&gt;</description></item><item><title>使用Docker镜像搭建ElasticSearch集群</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-03-run-elasticsearch-cluster-using-docker/</link><pubDate>Tue, 03 Nov 2020 22:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-03-run-elasticsearch-cluster-using-docker/</guid><description>&lt;p&gt;使用默认配置运行 ElaticSearch 的 Docker 镜像会启动一个单节点模式的服务，名为 docker-cluster。&lt;/p&gt;
&lt;p&gt;即便在同一个主机上启动多个 Docker 容器，在默认配置下，这些容器也不会自动组成 ES 集群。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/es/docker/single-docker.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;默认配置的 Docker 容器形成单节点 ElasticSearch 服务&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;ElasticSearch 官方文档中使用 Docker Compose 搭建 ElasticSearch 集群。
详情请访问以下文档：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html"&gt;Install Elasticsearch with Docker&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;笔者没使用过 Docker Compose，所以尝试通过直接创建 Docker 镜像来搭建 ElasticSearch 集群。&lt;/p&gt;
&lt;h2 id="目录挂载"&gt;目录挂载&lt;/h2&gt;
&lt;p&gt;Docker 镜像中 ElasticSearch 的根目录是 &lt;code&gt;/usr/share/elasticsearch&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以通过设置环境变量或使用配置文件的方式配置 ElasticSearch 服务。&lt;/p&gt;
&lt;p&gt;本文使用配置文件修改默认的参数。配置文件在 Docker 镜像中的位置是&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/share/elasticsearch/config/elasticsearch.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为了方便管理，配置文件保存在主机，通过文件挂载方式载入到镜像中。&lt;/p&gt;
&lt;p&gt;ElasticSearch 的数据目录是&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/share/elasticsearch/data
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为了方便升级和维护，将上述目录挂载到 Docker volume 数据卷中。&lt;/p&gt;
&lt;h2 id="网络"&gt;网络&lt;/h2&gt;
&lt;p&gt;默认 Docker 网络中的容器无法直接使用内部网络通讯。
所以为 ES 集群创建一个独立的 bridge 网络，名为 &lt;code&gt;message-net&lt;/code&gt;。
在该网络中的 Docker 容器已配置 DNS 服务，可以直接使用容器名称访问。&lt;/p&gt;</description></item><item><title>Dask应用：使用 Dask 并行抽取站点数据</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-02-create-station-data-using-dask/</link><pubDate>Mon, 02 Nov 2020 23:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-02-create-station-data-using-dask/</guid><description>&lt;p&gt;本文介绍如何使用 Dask 从多个文件中提取站点垂直廓线和剖面图数据。&lt;/p&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;最近在构建面向冬奥会服务的 GRAPES MESO 1KM 产品后处理的 ecFlow 系统 (grapes_meso_1km_post)。&lt;/p&gt;
&lt;p&gt;模式生成数据的信息如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;纬度 latitude：44.5 - 34.5&lt;/li&gt;
&lt;li&gt;经度 longitude：108 - 124&lt;/li&gt;
&lt;li&gt;分辨率：0.01 度，1km&lt;/li&gt;
&lt;li&gt;格点数 ni * nj：1601 * 1601&lt;/li&gt;
&lt;li&gt;时效 step：0 - 24 小时，逐小时间隔&lt;/li&gt;
&lt;li&gt;层次 pl：15 个等压面层，从 1000 hPa 到 100 hPa&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中一种产品是站点预报产品，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;站点的垂直廓线数据&lt;/li&gt;
&lt;li&gt;经过站点的沿经线和纬线的垂直剖面图数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;该数据由原始分辨率 GRIB 2 数据文件抽取生成，所有时效和所有变量都包含在同一个 NetCDF 文件中。
一共有 9 种变量，每种变量 3 类数据，每类数据 25 个时效，每个时效包含 15 层。&lt;/p&gt;
&lt;p&gt;当前任务脚本使用 &lt;strong&gt;NCL&lt;/strong&gt; 抽取数据并输出 NetCDF 文件。
经集成测试，每个站点的任务运行耗时均在 70 分钟左右。
对于计划逐小时运行的模式系统来说，这 &lt;strong&gt;可能&lt;/strong&gt; 不是一个理想的运行时间。&lt;/p&gt;</description></item><item><title>学习R语言：面向对象编程</title><link>https://blog.perillaroc.wang/post/2020/11/2020-11-01-study-r-oop/</link><pubDate>Sun, 01 Nov 2020 15:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/11/2020-11-01-study-r-oop/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;R 语言虽然与传统的面向对象语言 (如 C++，JAVA 和 Python) 不同，但也是一个明显的面向对象语言。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;R 中所有要素都是对象，从数字到字符串到矩阵&lt;/li&gt;
&lt;li&gt;R 支持封装 (encapsulation)&lt;/li&gt;
&lt;li&gt;R 类支持多态 (polymorphic)&lt;/li&gt;
&lt;li&gt;R 允许继承 (inheritance)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面介绍 R 语言中的 S3 和 S4 类。&lt;/p&gt;
&lt;h2 id="s3-类"&gt;S3 类&lt;/h2&gt;
&lt;p&gt;R 中原始的类结构，包含一个列表，附加类名属性和调度 (dispatch) 功能&lt;/p&gt;
&lt;h3 id="s3-泛型函数"&gt;S3 泛型函数&lt;/h3&gt;
&lt;p&gt;同一个函数可以针对不同的类调用不同的操作。&lt;/p&gt;
&lt;h3 id="实例线性模型函数-lm-中的-oop"&gt;实例：线性模型函数 &lt;code&gt;lm()&lt;/code&gt; 中的 OOP&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_out &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(y &lt;span style="color:#f92672"&gt;~&lt;/span&gt; x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;(lm_out)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;lm&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm_out
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = y ~ x)

Coefficients:
(Intercept) x 
 -3.0 3.5 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里使用的是 &lt;code&gt;print.lm()&lt;/code&gt; 方法。&lt;/p&gt;
&lt;p&gt;去掉 &lt;code&gt;lm_out&lt;/code&gt; 的类属性，再打印对象&lt;/p&gt;</description></item><item><title>GOLANG：使用SQLX库执行简单的SQL语句</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-30-golang-run-sql-statement-using-sqlx/</link><pubDate>Fri, 30 Oct 2020 21:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-30-golang-run-sql-statement-using-sqlx/</guid><description>&lt;p&gt;虽然 GOLANG 自带 SQL 库 database/sql，但为了简化代码提高编程效率，笔者推荐使用第三方库来处理数据库相关操作。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 &lt;a href="https://github.com/jmoiron/sqlx"&gt;SQLX&lt;/a&gt; 库连接 MySQL 数据库并执行简单的 SELECT 查询语句。&lt;/p&gt;
&lt;p&gt;示例代码来自 &lt;a href="https://github.com/nwpc-oper/nmc-typhoon-db-client"&gt;nwpc-oper/nmc-typhoon-db-client&lt;/a&gt; 项目，从 NMC 台风数据库中检索台风数据，计划用于 CMA-PI 上的业务系统。&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;连接 MySQL 数据库需要下载数据库驱动 &lt;a href="https://github.com/go-sql-driver/mysql"&gt;Go-MySQL-Driver&lt;/a&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go get -u github.com/go-sql-driver/mysql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下载 SQLX 库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go get github.com/jmoiron/sqlx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在源码中载入上述两个库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 	&lt;span style="color:#75715e"&gt;// ...skip...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/go-sql-driver/mysql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;github.com/jmoiron/sqlx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="创建数据库连接"&gt;创建数据库连接&lt;/h2&gt;
&lt;p&gt;SQLX 使用的数据库连接地址字符串与 SQLAlchemy 不同，格式如下所示&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;user:password@tcp(host:port)/database?param1=value1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为了解析时间字段，增加 &lt;code&gt;parseTime=true&lt;/code&gt; 参数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;sqlx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;conn&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Sprintf&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#e6db74"&gt;&amp;#34;%s:%s@tcp(%s)/%s?charset=utf8&amp;amp;parseTime=true&amp;amp;loc=Local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Auth&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Auth&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Password&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Host&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;DatabaseName&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;sqlx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;conn&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fatal&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;open db connection has error:&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;defer&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="执行查询"&gt;执行查询&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;sqlx.DB&lt;/code&gt; 对象的 &lt;code&gt;Queryx()&lt;/code&gt; 函数执行 SQL 语句，返回值中的 &lt;code&gt;rows&lt;/code&gt; 是一个迭代器。&lt;/p&gt;</description></item><item><title>Matplotlib绘制双坐标轴</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-29-matplotlib-draw-two-y-axis/</link><pubDate>Thu, 29 Oct 2020 22:55:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-29-matplotlib-draw-two-y-axis/</guid><description>&lt;p&gt;本文以绘制垂直廓线图为例说明在 Matplotlib 中如何在左右坐标轴上绘制不同的坐标。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;载入需要的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;本文绘制 GRAPES GFS 模式 2020 年 10 月 18 日 00 时次 105 时效北纬 40 度的平均垂直廓线图。&lt;/p&gt;
&lt;p&gt;查找数据文件路径&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2020101800&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;105h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;载入所有等压面层的温度场&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;short_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;level_type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;short_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;level_type,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/matplotlib/multi-y/field.png"&gt;
&lt;/figure&gt;

&lt;p&gt;提取北纬 40 度从 1000 hPa 到 20 hPa 的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; field&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sel(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pl&lt;span style="color:#f92672"&gt;=&lt;/span&gt;slice(&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sel(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; latitude&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;40&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;nearest&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/matplotlib/multi-y/data.png"&gt;
&lt;/figure&gt;

&lt;p&gt;计算均值&lt;/p&gt;</description></item><item><title>视界：Python开发使访问天气和气候数据更容易</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-27-view-python-developments-enable-easier-access-weather-and-climate-data/</link><pubDate>Wed, 28 Oct 2020 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-27-view-python-developments-enable-easier-access-weather-and-climate-data/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF 网站 2020 年 10 月 26 日新闻《&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2020/python-developments-enable-easier-access-weather-and-climate-data"&gt;Python developments enable easier access to weather and climate data&lt;/a&gt;》，版权归原作者所有。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/view/climetlab-eg-690px.jpg"&gt;
&lt;/figure&gt;

&lt;p&gt;ECMWF 正在开发 Python 库和接口，帮助人们更快，更高效地处理庞大的天气和气候数据集。
该中心还提供培训，帮助科学界和技术用户与服务进行对接，利用 ECMWF 的开源软件，并为其应用创造最大价值。&lt;/p&gt;
&lt;p&gt;作为数值天气预报 (Numerical weather prediction, NWP) 中心，ECMWF 生成并保存大量天气预报数据。
提供集合预测，提高模型分辨率和增加物理参数，意味着生成的数据量在不断增长。&lt;/p&gt;
&lt;p&gt;由 ECMWF 代表欧洲委员会 (European Commission) 运营的 &lt;a href="https://www.ecmwf.int/en/about/what-we-do/environmental-services"&gt;哥白尼服务&lt;/a&gt; (The Copernicus services) 还提供了大量数据集，数据的规模和受欢迎程度都在不断增长。&lt;/p&gt;
&lt;p&gt;这些数据集对决策者和科学家具有巨大的价值，但是人们常常无法充分利用数据集的潜力，因为它们对于时间紧迫的应用程序或训练机器学习算法来说太大了。&lt;/p&gt;
&lt;p&gt;Python 已成为地球系统科学中处理大型数据集的许多用户选择的编程语言，ECMWF 正在这一领域进行投资以帮助用户与其数据进行交互。&lt;/p&gt;
&lt;h3 id="简化访问"&gt;简化访问&lt;/h3&gt;
&lt;p&gt;多年来，ECMWF 一直在其关键软件包中提供 Python 接口，用于访问，处理和可视化气象数据。&lt;/p&gt;
&lt;p&gt;近年来，Metview，ECMWF 的气象工作站和批处理系统，也开发了 Python 接口，封装 ECMWF 提供的各种 Python 软件包的所有功能。
通过使用众所周知的高效 Python 数据结构，科学家和分析人员可以照常使用其所有数据，同时还提供利用已建立的 Python 科学生态系统的可能性。&lt;/p&gt;</description></item><item><title>学习R语言：数学运算与模拟</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-26-study-r-math/</link><pubDate>Mon, 26 Oct 2020 23:18:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-26-study-r-math/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;R 内置很多数学函数和统计分布函数。&lt;/p&gt;
&lt;h2 id="数学函数"&gt;数学函数&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exp()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log10()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqrt()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;abs()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sin()&lt;/code&gt;，&lt;code&gt;cos()&lt;/code&gt; 等三角函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min()&lt;/code&gt;，&lt;code&gt;max()&lt;/code&gt;：向量的最小、最大值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;which.min()&lt;/code&gt;，&lt;code&gt;which.max()&lt;/code&gt;：向量的最小、最大元素的位置索引&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pmin()&lt;/code&gt;，&lt;code&gt;pmax()&lt;/code&gt;：多个向量逐元素对比&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sum()&lt;/code&gt;，&lt;code&gt;prod()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cumsum()&lt;/code&gt;，&lt;code&gt;cumprod()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;round()&lt;/code&gt;，&lt;code&gt;floor()&lt;/code&gt;，&lt;code&gt;ceiling()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;factorial()&lt;/code&gt;：阶乘&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="扩展示例计算概率"&gt;扩展示例：计算概率&lt;/h3&gt;
&lt;p&gt;假设有 n 个独立事件，其中第 i 个时间的发生概率是 P_i，求恰好有一个事件发生的概率。&lt;/p&gt;
&lt;p&gt;$$
\sum_{i=1}^{n} p_i(1 - p1)&amp;hellip;(1-p_{i-1})(1 - p_{i+1})&amp;hellip;(1-p_n)
$$&lt;/p&gt;
&lt;p&gt;向量 &lt;code&gt;p&lt;/code&gt; 包含所有事件的概率 P_i，&lt;code&gt;exactly.one()&lt;/code&gt; 函数计算只有一个事件发生的概率&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exactly.one &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(p) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; not.p &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; p
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(p)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; total &lt;span style="color:#f92672"&gt;+&lt;/span&gt; p[i] &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;prod&lt;/span&gt;(not.p[&lt;span style="color:#f92672"&gt;-&lt;/span&gt;i])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;(total)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;共有三个事件，概率如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;计算只有一个事件发生的概率&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;exactly.one&lt;/span&gt;(p)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 0.398
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="累积和与累积乘积"&gt;累积和与累积乘积&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cumsum&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 12 17 30
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cumprod&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 12 60 780
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="最大值和最小值"&gt;最大值和最小值&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matrix&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ncol&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1] [,2]
[1,] 1 2
[2,] 5 3
[3,] 6 2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;min()&lt;/code&gt; 返回全局最小值&lt;/p&gt;</description></item><item><title>ecFlow笔记：基于ecFlow构建后台服务监控系统</title><link>https://blog.perillaroc.wang/post/2020/01/2020-01-15-ecflow-notebook-service-checker/</link><pubDate>Sat, 24 Oct 2020 15:21:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/01/2020-01-15-ecflow-notebook-service-checker/</guid><description>&lt;p&gt;本文介绍如何使用 ecFlow 定时检查后台程序运行情况，实现对 HPC 登录节点上后台服务的监控，并在程序退出时实现自动重启。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;前两年笔者开发的监控程序通常部署在 HPC 外的 Linux 服务器上，使用 SSH 协议或者 TCP 端口远程连接 HPC 获取监控数据。
但这类程序存在不少问题。&lt;/p&gt;
&lt;p&gt;比如下面两个近期没有更新的项目：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nwpc-hpc-exporter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-hpc-exporter"&gt;nwpc-oper/nwpc-hpc-exporter&lt;/a&gt; 项目为 Prometheus 提供 HPC 监控指标。
该项目运行在 Linux 服务器上，通过 SSH 协议使用账户名和密码远程连接到 HPC 执行命令行程序，定时获取 HPC 的运行状态。&lt;/p&gt;
&lt;p&gt;保持与高性能计算的 SSH 长时间连接并不是百分之百可靠的。
所以，需要设置重新连接机制。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nwpc-ecflow-collector&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-ecflow-collector"&gt;nwpc-oper/nwpc-ecflow-collector&lt;/a&gt; 项目使用 ecFlow 的 Python API 获取系统的运行状态。&lt;/p&gt;
&lt;p&gt;该项目在 NWPC 监控平台 (NWPC Monitor Platform, NMP) 中应用时，从 Linux 服务器远程连接 ecFlow 服务绑定的 TCP 端口，获取节点运行状态。&lt;/p&gt;
&lt;p&gt;但 ecFlow 的 API 没有对数据进行压缩，对于挂载任务数比较多的服务（例如集合预报和产品后处理系统等），整个获取过程速度很慢。&lt;/p&gt;
&lt;p&gt;为此，笔者开发 &lt;a href="https://github.com/nwpc-oper/ecflow-client-cpp"&gt;nwpc-oper/ecflow-client-cpp&lt;/a&gt; 项目，将 ecFlow 的采集程序放到高性能计算机的登陆节点上，使用 gRPC 向外提供服务。&lt;/p&gt;</description></item><item><title>NWPC消息平台：模式运行时长预测消息</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-22-nwpc-message-model-run-time-predict-message/</link><pubDate>Thu, 22 Oct 2020 22:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-22-nwpc-message-model-run-time-predict-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWPC 消息平台中使用 &lt;strong&gt;模式运行时长预测消息&lt;/strong&gt; (Model Run Time Predict Message) 记录对模式积分任务运行时长的预测结果。&lt;/p&gt;
&lt;h2 id="模式运行时长预测"&gt;模式运行时长预测&lt;/h2&gt;
&lt;p&gt;NWPC 已在业务环境中实时预测模式积分任务总体耗时。具体算法请参看以下文章：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;恒定步长（全球模式）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-11-nwpc-notebook-predict-using-linear-regression-for-step-time/"&gt;NWPC笔记：预测模式积分时长 - 线性回归&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;动态步长（区域模式）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-23-nwpc-notebook-predict-step-time-for-meso-3km/"&gt;NWPC笔记：预测动态步长模式积分时长 - 线性回归&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;实际的预测系统如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/message/model-run-time-predict/check-grapes-gfs-gmf-system.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES GFS 模式积分时长预测系统&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;对于每个时次，预测系统通过检测模式输出文件 (二进制postvar文件)，实时获得模式积分进度。
当积分进行到预设时效，即某个时效文件生成时，预测系统会启动预测任务，根据当前模式积分的日志输出预测总体运行时间。
上图所示的 GRAPES GFS 预测系统中每隔 24 小时进行一次预测。&lt;/p&gt;
&lt;p&gt;因为检测文件是否输出有滞后性，同时在 PI 上启动 Python 程序有一定的延时，预测程序实际运行时模式积分会超过预定的时效。
为了尽可能利用数据，预测程序会使用最新的模式积分时长数据。&lt;/p&gt;
&lt;p&gt;模式运行时长预测消息用于记录对积分任务总体耗时的预测。&lt;/p&gt;
&lt;h2 id="消息结构"&gt;消息结构&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;模式运行时长预测消息&lt;/strong&gt; (ModelRunTimePredictMessage) 符合 NWPC 消息平台的 &lt;strong&gt;事件消息&lt;/strong&gt; (EventMessage) 规范，消息结构如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/message/model-run-time-predict/model-run-time-predict-v3.png"&gt;
&lt;/figure&gt;

&lt;p&gt;数据段由以下几个部分构成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;system&lt;/code&gt;：系统名称&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start_time&lt;/code&gt;：起报时次，格式 &lt;code&gt;YYYY-MM-DDThh:mm:ss&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;request&lt;/code&gt;：请求参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;current&lt;/code&gt;：积分当前情况&lt;/li&gt;
&lt;li&gt;&lt;code&gt;predict&lt;/code&gt;：预测结果&lt;/li&gt;
&lt;li&gt;&lt;code&gt;model&lt;/code&gt;：模型参数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="request"&gt;request&lt;/h3&gt;
&lt;p&gt;request 字段记录进行预测时的请求参数，对应预测系统中预定义的时效，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;forecast_time&lt;/code&gt;：预报时效，表示为时间段，符合 ISO 8601 格式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;valid_time&lt;/code&gt;：预报时刻，格式 &lt;code&gt;YYYY-MM-DDThh:mm:ss&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="current"&gt;current&lt;/h3&gt;
&lt;p&gt;current 字段记录进行预测时，模式积分的当前运行情况，包括：&lt;/p&gt;</description></item><item><title>ISLR实验：线性模型扩展</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-21-islr-lab-chap03-linear-extension/</link><pubDate>Wed, 21 Oct 2020 21:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-21-islr-lab-chap03-linear-extension/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《3.6 实验：线性回归》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;标准线性回归模型有两个最重要的假设：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可加性&lt;/strong&gt; (additive)：预测变量 X_j 的变化对响应变量 Y 产生的影响与其他预测变量的取值无关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线性&lt;/strong&gt; (linear)：无论 X_j 取何值，X_j 变化一个单位引起的响应变量 Y 的变化是恒定的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上述假设在实际问题中常常被违背。&lt;/p&gt;
&lt;p&gt;本文介绍一些扩展的线性模型，继续使用 Boston 数据集。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(MASS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="交互项"&gt;交互项&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;交互项&lt;/strong&gt; (interaction) 去除可加性假设，考虑变量之间的交互作用 (interaction)。&lt;/p&gt;
&lt;p&gt;使用两个变量的乘积作为一个交互项。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lm()&lt;/code&gt; 支持交互项。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lstat:black&lt;/code&gt; 将 lstat 和 black 的交互项加入到模型中。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lstat*age&lt;/code&gt; 将 lstat，age 和交互项 lstat * age 作为预测变量，是 &lt;code&gt;lstat + age + lstat:age&lt;/code&gt; 的简写&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm.fit.inter &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(medv&lt;span style="color:#f92672"&gt;~&lt;/span&gt;lstat &lt;span style="color:#f92672"&gt;*&lt;/span&gt; age, data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Boston)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm.fit.inter
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = medv ~ lstat * age, data = Boston)

Coefficients:
(Intercept) lstat age lstat:age 
 36.0885359 -1.3921168 -0.0007209 0.0041560 
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm.fit.inter)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = medv ~ lstat * age, data = Boston)

Residuals:
 Min 1Q Median 3Q Max 
-15.806 -4.045 -1.333 2.085 27.552 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) 36.0885359 1.4698355 24.553 &amp;lt; 2e-16 ***
lstat -1.3921168 0.1674555 -8.313 8.78e-16 ***
age -0.0007209 0.0198792 -0.036 0.9711 
lstat:age 0.0041560 0.0018518 2.244 0.0252 * 
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.149 on 502 degrees of freedom
Multiple R-squared: 0.5557,	Adjusted R-squared: 0.5531 
F-statistic: 209.3 on 3 and 502 DF, p-value: &amp;lt; 2.2e-16
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;实验分层原则&lt;/strong&gt; (hierarchical principle) 规定：&lt;/p&gt;</description></item><item><title>ISLR实验：多元线性回归</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-20-islr-lab-chap03-multi-linear/</link><pubDate>Tue, 20 Oct 2020 23:16:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-20-islr-lab-chap03-multi-linear/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《3.6 实验：线性回归》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;使用 Boston 数据集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(MASS)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;library&lt;/span&gt;(ISLR)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="拟合"&gt;拟合&lt;/h2&gt;
&lt;p&gt;语句 &lt;code&gt;lm(y ~ x1 + x2)&lt;/code&gt; 建立两个预测变量 &lt;code&gt;x1&lt;/code&gt;，&lt;code&gt;x2&lt;/code&gt; 的拟合模型&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lm.fit.2 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lm&lt;/span&gt;(medv &lt;span style="color:#f92672"&gt;~&lt;/span&gt; lstat &lt;span style="color:#f92672"&gt;+&lt;/span&gt; age, data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Boston)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;summary()&lt;/code&gt; 函数输出预测变量的回归系数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;summary&lt;/span&gt;(lm.fit.2)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Call:
lm(formula = medv ~ lstat + age, data = Boston)

Residuals:
 Min 1Q Median 3Q Max 
-15.981 -3.978 -1.283 1.968 23.158 

Coefficients:
 Estimate Std. Error t value Pr(&amp;gt;|t|) 
(Intercept) 33.22276 0.73085 45.458 &amp;lt; 2e-16 ***
lstat -1.03207 0.04819 -21.416 &amp;lt; 2e-16 ***
age 0.03454 0.01223 2.826 0.00491 ** 
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.173 on 503 degrees of freedom
Multiple R-squared: 0.5513,	Adjusted R-squared: 0.5495 
F-statistic: 309 on 2 and 503 DF, p-value: &amp;lt; 2.2e-16
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;绘制诊断图&lt;/p&gt;</description></item><item><title>ISLR实验：简单线性回归</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-19-islr-lab-chap03-simple-linear/</link><pubDate>Mon, 19 Oct 2020 23:11:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-19-islr-lab-chap03-simple-linear/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《3.6 实验：线性回归》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简单线性关系"&gt;简单线性关系&lt;/h2&gt;
&lt;p&gt;$$
Y \approx \beta_{0} + \beta_{1}X
$$&lt;/p&gt;
&lt;p&gt;通过拟合计算模型参数 \beta_{0} 和 \beta_{1}，使用下面的表达式计算预测值&lt;/p&gt;
&lt;p&gt;$$
\hat{y} = \hat{\beta_{0}} + \hat{\beta_{1}}X
$$&lt;/p&gt;
&lt;h2 id="评价准确性"&gt;评价准确性&lt;/h2&gt;
&lt;p&gt;假设 X 和 Y 之间的真实关系可以表示为&lt;/p&gt;
&lt;p&gt;$$
Y = \beta_{0} + \beta_{1}X + \epsilon
$$&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;beta_{0} 是截距，当 X=0 时 Y 的值&lt;/li&gt;
&lt;li&gt;beta_{1} 是斜率，当 X 增加一个单位是 Y 的平均增幅&lt;/li&gt;
&lt;li&gt;epsilon 是均值为零的随机误差项&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="残差"&gt;残差&lt;/h3&gt;
&lt;p&gt;观测到的响应值和用线性模型预测出的响应值之间的差距&lt;/p&gt;
&lt;p&gt;$$
e_{i} = y_{i} - \hat{y_{i}}
$$&lt;/p&gt;
&lt;h3 id="残差平方和"&gt;残差平方和&lt;/h3&gt;
&lt;p&gt;residual sum of squares，RSS&lt;/p&gt;
&lt;p&gt;$$
RSS = e_{1}^{2} + e_{2}^{2} + \cdots + e_{n}^{2}
$$&lt;/p&gt;</description></item><item><title>学习R语言：编程结构</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-18-study-r-programming/</link><pubDate>Sun, 18 Oct 2020 13:04:30 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-18-study-r-programming/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;注：从本文开始，笔者使用 RStudio 代替 Jupyter Lab 执行代码&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="控制语句"&gt;控制语句&lt;/h2&gt;
&lt;h3 id="循环"&gt;循环&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;for&lt;/code&gt;，&lt;code&gt;while&lt;/code&gt;，&lt;code&gt;repeat&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (n &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; x) &lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(n)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 5
[1] 12
[1] 13
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 13
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 13
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;TRUE&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 13
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;repeat&lt;/code&gt; 相当于 &lt;code&gt;while(TRUE)&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; i &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;i
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 13
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;next&lt;/code&gt; 类似 C++ 中的 &lt;code&gt;continue&lt;/code&gt;&lt;/p&gt;</description></item><item><title>NWPC消息平台：验证 ecFlow 命令消息</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-15-nwpc-message-validate-ecflow-client-message/</link><pubDate>Thu, 15 Oct 2020 21:55:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-15-nwpc-message-validate-ecflow-client-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWPC 消息平台引入 ecFlow 命令消息 (Ecflow Client Message) 用于代替无法实时获取更新的 ecFlow 日志。&lt;/p&gt;
&lt;p&gt;在提供实时数据之前，首先要确认 NWPC 消息平台记录的 ecFlow 命令事件是否与 ecFlow 日志相吻合。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; tqdm.notebook &lt;span style="color:#f92672"&gt;import&lt;/span&gt; tqdm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;本文数据来自目前已启用 ecFlow 命令消息的 globalchartos 系统，分别从 ecFlow 日志和 NWPC 消息存储中获取事件记录。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;globalchartos 系统为 WMC-BJ 网站生成 GRAPES GFS 模式的图形产品&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了尽可能简化处理过程，仅选用 globalchartos 系统 00 时次。&lt;/p&gt;
&lt;h3 id="ecflow-日志"&gt;ecFlow 日志&lt;/h3&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt; 项目从 ecFlow 日志中提取任务节点执行 &lt;code&gt;ecflow_client&lt;/code&gt; 子命令的日志条目。&lt;/p&gt;
&lt;p&gt;关于日志解析的详细信息，请参看以下文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/"&gt;ecFlow日志解析 - 通用字段&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-18-ecflow-notebook-parse-child-command-log/"&gt;ecFlow日志解析 - child 命令记录&lt;/a&gt;》&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="准备数据"&gt;准备数据&lt;/h4&gt;
&lt;p&gt;为了加快日志解析，使用 &lt;code&gt;grep&lt;/code&gt; 命令提取 00 时次的记录。&lt;/p&gt;</description></item><item><title>NWPC消息平台：ecFlow 命令消息</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-12-nwpc-message-ecflow-client-message/</link><pubDate>Mon, 12 Oct 2020 22:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-12-nwpc-message-ecflow-client-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWPC 消息平台中使用的 ecFlow 命令消息 (Ecflow Client Message) 用于记录 ecFlow 命令行程序 &lt;code&gt;ecflow_client&lt;/code&gt; 的调用。&lt;/p&gt;
&lt;h2 id="ecflow_client-命令"&gt;ecflow_client 命令&lt;/h2&gt;
&lt;h3 id="简介"&gt;简介&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ecflow_client&lt;/code&gt; 命令可以实现与 ecFlow 服务的通讯。&lt;/p&gt;
&lt;p&gt;ecFlow 实际执行的任务脚本使用 &lt;code&gt;ecflow_client&lt;/code&gt; 的子命令 (child command) 实现任务与 ecFlow 服务的通讯。
比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--init&lt;/code&gt;：告知服务任务开始运行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--complete&lt;/code&gt;：告知服务任务运行完成&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--aborted&lt;/code&gt;：告知服务任务运行结束&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--event&lt;/code&gt;：触发 event&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--meter&lt;/code&gt;：修改 meter 值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--label&lt;/code&gt;：修改 label 值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上述命令会修改 ecFlow 服务中节点的运行状态或属性。&lt;/p&gt;
&lt;p&gt;服务接收到的每条命令都会在 ecFlow 日志文件中记录，从这些记录中可以分析得到节点的状态变化信息。&lt;/p&gt;
&lt;p&gt;有关日志条目更详细的介绍请查看以下文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-14-ecflow-notebook-ecflow-log-introduction/"&gt;ecFlow日志简介&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-15-ecflow-notebook-ecflow-log-type/"&gt;ecFlow日志分类&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/"&gt;ecFlow日志解析 - 通用字段&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-17-ecflow-notebook-parse-status-log/"&gt;ecFlow日志解析 - 状态变化记录&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-18-ecflow-notebook-parse-child-command-log/"&gt;ecFlow日志解析 - child 命令记录&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-23-ecflow-notebook-parse-client-command/"&gt;ecFlow日志解析 - client 命令记录&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-24-ecflow-notebook-parse-server-command-log/"&gt;ecFlow日志解析 - 服务端记录&lt;/a&gt;》&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="背景"&gt;背景&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;既然 ecFlow 日志已保存记录，为什么还要额外记录命令调用？&lt;/p&gt;</description></item><item><title>Meteva笔记：计算格点降水的列联表</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-11-meteva-notebook-grid-rain-table/</link><pubDate>Sun, 11 Oct 2020 16:09:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-11-meteva-notebook-grid-rain-table/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Meteva 是由 nmc 开源的全流程检验程序库，提供了常用的各种气象预报检验评估的算法函数，气象检验分析的图片和表格型产品的制作函数，以及检验评估系统示例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文以 24 小时累积降水为例，说明如何计算格点场二分类预报的列联表。
同时会介绍如何使用 &lt;a href="https://github.com/nmcdev/meteva"&gt;Meteva&lt;/a&gt; 计算列联表。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;载入需要使用到的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参数"&gt;参数&lt;/h2&gt;
&lt;p&gt;区域范围，仅计算区域内的观测&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;145&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;降水阈值，单位为 mm。为每个阈值分别计算列联表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thresholds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;观测时刻，2020 年 8 月 1 日 00 时次&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_date &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-08-01 00:00:00&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择 12 时次预报&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_start_hour &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;数据目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_root &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/g2/nwp_vfy/operation/EC&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;h3 id="预报"&gt;预报&lt;/h3&gt;
&lt;p&gt;对于 &lt;code&gt;current_date&lt;/code&gt; 时刻 &lt;code&gt;current_forecast_hour&lt;/code&gt; 时效预报所对应的起报时间&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;step_start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; current_date &lt;span style="color:#f92672"&gt;-&lt;/span&gt; current_forecast_hour
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;step_start_time
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Timestamp(&amp;#39;2020-07-30 12:00:00&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;即 036 时效是 2020-08-01 00 时次对应的起报时次是 2020-07-30 12 时次&lt;/p&gt;</description></item><item><title>读《治国理政》第三卷有感</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-10-thoughts-after-reading-the-governace-of-china-volumn-three/</link><pubDate>Sat, 10 Oct 2020 23:48:56 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-10-thoughts-after-reading-the-governace-of-china-volumn-three/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是为“学用新思想、笔谈千字文”活动写的千字文。耗时一个半小时，时间仓促，思考不周，仅作为记录。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在《治国理政》第三卷第七专题《形成全面开放新格局》中，在《开放合作 命运与共——在第二届中国国际进口博览会开幕式上的主旨演讲》文中指出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;站在新的历史起点，中国开放的大门只会越开越大。中国共产党刚刚举行了十九届四中全会，制定了关于坚持和完善中国特色社会主义制度、推进国家治理体系和治理能力现代化若干重大问题的决定，其中包括很多深化改革、扩大开放的重要举措。我们将坚持对外开放的基本国策，坚持以开放促改革、促发展、促创新，持续推进更高水平的对外开放。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;身为一名国家级数值预报业务系统的建设者，我始终认为开放合作是气象行业发展前行的重要动力。
我主要从事 GRAPES 数值预报业务系统建设、运维和支撑系统的开发等工作。
数值预报模式是一个规模庞大、环节众多的复杂系统，实时运行的业务会涉及多个单位的多个部门，开放合作对于保障业务系统的稳定运行至关重要。
我所在的 NWPC 系统业务室一直保持与气象部门内外各个单位的紧密合作，致力于推动数值预报业务系统全链条流程建设，保障数值预报业务系统的稳定运行，为预报员等用户及时提供预报产品。
我们积极与信息中心、卫星中心、探测中心等气象部门内单位合作，打通观测资料获取通道，让更多的观测数据能进入到模式系统中；
我们通过多种方式与国内外大学、研究机构等单位合作，共同开发 GRAPES 模式，提升模式的预报性能；
我们还通过信息中心向部门内单位实时提供 GRAPES 模式的预报产品，并为国内外大量用户提供定制化的数据与图形产品。&lt;/p&gt;
&lt;p&gt;在《开放共创繁荣 创新引领未来——在博鳌亚洲论坛2018年年会开幕式上的主旨演讲》文中指出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当今世界，开放融通的潮流滚滚向前。人类社会发展的历史告诉我们，开放带来进步，封闭必然落后。世界已经成为你中有我、我中有你的地球村，各国经济社会发展日益相互联系、相互影响，推进互联互通、加快融合发展成为促进共同繁荣发展的必然选择。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;开放合作同样也为气象行业发展的必然选择。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;中国气象局正在建设气象大数据云平台，计划到 2022 年，基本建成技术先进、布局合理、岗位优化、流程贯通、系统集约的研究型业务新格局。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWPC 系统业务室也积极推进 GRAPES 数值预报业务系统与气象大数据云平台的融合。
我们已将业务运行维护系统与“天镜”平台对接，通过“天镜”平台提供的 API 接口实时将报警信息发送到微信客户端。
我们已开发基于加工流水线的产品后处理系统，为后续将整个产品制作系统迁移到大数据云平台打下坚实的基础。
同时，我们正在制定融入方案。按照目前的规划，数值预报业务系统将在明年开始启动融入气象大数据云平台的进程。
计划从产品后处理入手，并过渡到资料前处理等步骤。
最终将所有非并行计算的任务都迁移到云平台中，而高性能计算机上仅保留并行计算任务。&lt;/p&gt;
&lt;p&gt;无论从整个业务系统构建和维护角度，还是从我个人职业发展的角度来看，大数据云平台都会带来严峻的挑战。
但在《共建创新包容的开放型世界经济——在首届中国国际进口博览会开幕式上的主旨演讲》文中指出&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我相信，只要我们保持战略定力，全面深化改革开放，深化供给侧结构性改革，下大气力解决存在的突出矛盾和问题，中国经济就一定能加快转入高质量发展轨道，中国人民就一定能战胜前进道路上的一切困难挑战，中国就一定能迎来更加光明的发展前景。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以只要坚持开发合作的精神，没有什么困难是无法克服的，也没有什么挑战是无法战胜的。
我坚信，在整个部门的共同努力下，明年必将会按时完成数值预报业务系统与大数据云平台的融入工作，届时将极大简化高性能计算机上的业务系统流程，同时全面改进当前的产品制作流程，为产品制作系统的后续发展奠定基础。&lt;/p&gt;
&lt;p&gt;当然，我们数值预报业务系统还有不少改进和优化的空间，在支撑业务系统运行的关键软件工具方面仍然严重依赖国外同行的开源项目。
比如运行调度使用 ECMWF 开发的 ecFlow 工具，数据处理使用 ECMWF 开发的 ecCodes 和 NCEP 开发的 wgrib2 工具等等。
尽管是否需要重复造轮子尚未有定论，但我始终认为 NWPC 也应该加入软件开源的大家庭中，积极推广我们的工作成果，同时也能促进我们持续开发功能完善的工具，增强在模式支撑工具领域的影响力。
虽然开发类似 ecFlow 等工具需要长时间的积累，但如果因为困难而退缩，那就永远也无法诞生类似的成果。
正如在《在庆祝海南建省办经济特区30周年大会上的讲话》文中指出&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;历史从不眷顾因循守旧、满足现状者，机遇属于勇于创新、永不自满者。一切伟大成就都是接续奋斗的结果，一切伟大事业都需要在继往开来中推进。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;愿我们坚持开放合作的精神，为我国气象现代化贡献自己的力量。&lt;/p&gt;</description></item><item><title>NWPC消息平台：产品事件消息</title><link>https://blog.perillaroc.wang/post/2020/10/2020-10-01-nwpc-message-production-message/</link><pubDate>Fri, 09 Oct 2020 09:46:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/10/2020-10-01-nwpc-message-production-message/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NWPC 消息平台使用的产品事件消息 (Production Event Message) 用于记录与产品相关的事件，比如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;产品已生成&lt;/li&gt;
&lt;li&gt;产品生成出错&lt;/li&gt;
&lt;li&gt;产品已完成上传&lt;/li&gt;
&lt;li&gt;产品上传出错&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文首先介绍通用的事件消息结构，然后介绍目前已在 NWPC 消息平台中使用的产品消息结构。&lt;/p&gt;
&lt;h2 id="事件消息"&gt;事件消息&lt;/h2&gt;
&lt;p&gt;NWPC 消息平台使用事件消息 (Event Message) 表示需要记录的某个事件。&lt;/p&gt;
&lt;h3 id="消息结构"&gt;消息结构&lt;/h3&gt;
&lt;p&gt;通用事件消息的结构如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-message/message/production/event-message.png"&gt;
&lt;/figure&gt;

&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app&lt;/code&gt;：发出事件的应用名，例如 &lt;code&gt;nwpc-message-client&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;：事件类型，例如 &lt;code&gt;production&lt;/code&gt; 表示产品消息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time&lt;/code&gt;：事件发出时的时间戳，使用 RFC 3339 格式的字符串表示&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt;：数据字段，键值对，与事件相关的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了保持消息的一致性，每种类型的消息都需要预先定义数据字段。
但正如下面即将介绍的产品消息，每个事件消息不一定包含该类型消息所有的数据字段，可以从备选字段中选择需要的字段。
换一种说法就是，每类消息还可能有子类型。&lt;/p&gt;
&lt;h3 id="事件状态"&gt;事件状态&lt;/h3&gt;
&lt;p&gt;事件消息的一个重要组成部分就是事件的状态。&lt;/p&gt;
&lt;p&gt;NWPC 消息平台借鉴 ecFlow 的节点运行状态，使用统一的事件状态 (&lt;code&gt;EventStatus&lt;/code&gt;) 定义，包含以下几种状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;unknown&lt;/code&gt;：未知状态，默认值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete&lt;/code&gt;：完成&lt;/li&gt;
&lt;li&gt;&lt;code&gt;queued&lt;/code&gt;：排队&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aborted&lt;/code&gt;：出错&lt;/li&gt;
&lt;li&gt;&lt;code&gt;submitted&lt;/code&gt;：提交&lt;/li&gt;
&lt;li&gt;&lt;code&gt;active&lt;/code&gt;：运行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;suspended&lt;/code&gt;：挂起&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="产品消息"&gt;产品消息&lt;/h2&gt;
&lt;p&gt;产品消息用于记录与产品制作、分发等步骤相关的事件。&lt;/p&gt;
&lt;p&gt;目前只记录产品完成上传（分发）的事件。&lt;/p&gt;
&lt;p&gt;产品事件消息由三部分构成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;产品信息：定义事件描述的是何种产品&lt;/li&gt;
&lt;li&gt;产品属性：描述在某产品系列中某个特定产品（单个文件）的属性&lt;/li&gt;
&lt;li&gt;事件状态：事件类型和事件状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="产品定义"&gt;产品定义&lt;/h3&gt;
&lt;p&gt;首先要定义产品的类型。
产品定义包含以下四个必选字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;system&lt;/code&gt;：系统名称&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stream&lt;/code&gt;：产品流&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;：产品类型&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;：产品名称&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="系统名称"&gt;系统名称&lt;/h4&gt;
&lt;p&gt;NWPC 同时运行多套业务数值预报系统，包括 2 个全球模式系统和 4 个区域模式系统：&lt;/p&gt;</description></item><item><title>2020年第三季度工作总结</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-30-2020-q3-summary/</link><pubDate>Wed, 30 Sep 2020 22:43:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-30-2020-q3-summary/</guid><description>&lt;p&gt;随着全年最重要的任务 &lt;strong&gt;业务系统升级&lt;/strong&gt; 于第二季度完成，我在最近三个月有充足的时间做自己感兴趣的工作，开始进入对转型的探索期中。
不过，转型不是想一想就能实现的，尤其是像我这样全凭自己探索方向，缺乏足够的指导，连最终的目标都没有确定，就更不用说能否成功了。&lt;/p&gt;
&lt;p&gt;在总结第二季度工作时，我已列出第三季度的计划。
虽然我确实是按照计划开展了后续工作，但却没能实现所有的目标。&lt;/p&gt;
&lt;h2 id="系统建设"&gt;系统建设&lt;/h2&gt;
&lt;p&gt;业务系统没有大规模的升级更新，但因为运行环境和产品需求，进行了一些维护级更新。&lt;/p&gt;
&lt;h3 id="ftp-切换"&gt;FTP 切换&lt;/h3&gt;
&lt;p&gt;因服务器下线等问题，调整 FTP 上传，将 GRIB 2 产品发送给 CTS。
最终目标是不再直接向外单位用户发送产品，而是将产品全部传输至信息中心，再由信息中心进行分发。&lt;/p&gt;
&lt;p&gt;这种方式会极大降低运维成本，也符合预报司最新的数据管理规定。
但增加的中间环节会导致与最终用户脱离，我们无法明确知道产品到底是哪些用户在用。
之前就已有类似的情况发生，最终用户并不知道数据的流转方式，缺数据时用户的第一反应很可能是产品没有正常生成。
不过，我们部门更关注如何保证产品成功发送，对于提供服务的时效性并不是关注的重点。&lt;/p&gt;
&lt;p&gt;产品分发管理一直是业务系统中欠缺，但又不是必须的功能。
我曾经做过一部分工作，但发现想要将分发管理与实际分发相结合，需要重构产品分发流程，在现有系统框架下很难实现，就不再继续这方面的工作。
后续会将产品制作全部放到气象大数据平台中，也许可以重新开展产品分发方面的工作。&lt;/p&gt;
&lt;h3 id="新产品"&gt;新产品&lt;/h3&gt;
&lt;p&gt;GRAPES TYM 后处理增加为 NMC 制作的台风动画 GIF 产品。&lt;/p&gt;
&lt;p&gt;我认为针对单一特殊需求而在业务系统中增加新任务不是最佳实践，业务系统应该保持稳定。
不过，我们暂时没有其他手段能实时制作产品，也许气象大数据云平台能提供合适的工具。&lt;/p&gt;
&lt;h3 id="气象大数据云平台培训"&gt;气象大数据云平台培训&lt;/h3&gt;
&lt;p&gt;参加了 7 月 30 日信息中心关于气象大数据云平台的在线培训。
因为没有可用账户，缺乏使用经验，所以收获有限，具体讨论参见：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/07/2020-07-30-thoughts-about-cmadaas-training/"&gt;气象大数据云平台培训感想&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;另外在为基于加工流水线的产品后处理项目准备文字材料时，翻译了 ECMWF 之前的一篇报道&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-05-view-the-hermes-service-for-scalable-post-processing/"&gt;视界：用于可扩展后处理的 Hermes 服务&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="运维"&gt;运维&lt;/h2&gt;
&lt;p&gt;应当从工作中提炼科学问题，不能仅停留在工具开发层面。
第三季度，我没能从运维工作中总结出新的科学问题，也就是说没能设计出与运维相关的新的算法。&lt;/p&gt;
&lt;p&gt;这是一件值得警惕的事情，不能为了开发而开发，应该将开发工具当成验证算法的一种方式。
我应该更关注工具背后所使用的算法，研究已有算法是否有改进空间，研究运维需求是否能衍生出新的算法。&lt;/p&gt;
&lt;p&gt;最近看到国家气象信息中心发布第一批和第二批 &lt;strong&gt;创新团队骨干成员遴选公告&lt;/strong&gt;，其中部分岗位职责正好与数值预报模式系统业务系统相关，可以作为提炼科学问题的参考。
比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模式运行流程调度技术（自主的流程调度原型系统）&lt;/li&gt;
&lt;li&gt;气象数值模式特征分析&lt;/li&gt;
&lt;li&gt;流水线调度和算法集成技术研发（云平台加工流水线与HPC并行计算的调度协同）&lt;/li&gt;
&lt;li&gt;数据全生命周期监控技术研发&lt;/li&gt;
&lt;li&gt;业务配置与控制技术研发&lt;/li&gt;
&lt;li&gt;智能化运维技术研究&lt;/li&gt;
&lt;li&gt;业务报表及评估分析&lt;/li&gt;
&lt;li&gt;告警通知机制及可视化技术研发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下阶段可以参照上述岗位及相应的职责要求，思考后续应该如何开展工作。&lt;/p&gt;
&lt;h3 id="值班网站"&gt;值班网站&lt;/h3&gt;
&lt;p&gt;在全科同志的共同推动下，值班系统的报警质量已有显著的提升。&lt;/p&gt;
&lt;p&gt;8 月份 HW 行动期间，旧版值班系统网段被封，无法继续使用。
尝试使用新版值班网站记录值班日志，可以满足日常维护记录的需求。
计划最晚于明年汛期之前正式切换，替代旧版值班系统。&lt;/p&gt;</description></item><item><title>学习R语言：因子和表</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-28-study-r-factor-and-table/</link><pubDate>Mon, 28 Sep 2020 23:11:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-28-study-r-factor-and-table/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因子 (factor) 的设计思想来源于统计学中的名义变量 (nominal variables)，或称之为分类变量 (categorical variables)。
这种变量的值本质上不是数字，而是对应为分类。&lt;/p&gt;
&lt;h2 id="因子与水平"&gt;因子与水平&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xf &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;factor&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(xf)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 5 12 13 12
Levels: 5 12 13
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;xf 中的不同数值 (5, 12, 13) 就是水平 (level)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;(xf)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; Factor w/ 3 levels &amp;#34;5&amp;#34;,&amp;#34;12&amp;#34;,&amp;#34;13&amp;#34;: 1 2 3 2
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;unclass&lt;/span&gt;(xf))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 1 2 3 2
attr(,&amp;#34;levels&amp;#34;)
[1] &amp;#34;5&amp;#34; &amp;#34;12&amp;#34; &amp;#34;13&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上述结果中第一行表示水平列表的序号，即第一个值是第一个水平，即 5。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;unclass&lt;/span&gt;(xf))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; int [1:4] 1 2 3 2
 - attr(*, &amp;#34;levels&amp;#34;)= chr [1:3] &amp;#34;5&amp;#34; &amp;#34;12&amp;#34; &amp;#34;13&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因子的长度是数据的长度&lt;/p&gt;</description></item><item><title>学习R语言：数据框</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-27-study-r-data-frame/</link><pubDate>Sun, 27 Sep 2020 22:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-27-study-r-data-frame/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;数据框 (&lt;code&gt;data.frame&lt;/code&gt;) 类似矩阵，有行和列，但数据框中的每一列可以使不同的模式 (mode)。&lt;/p&gt;
&lt;h2 id="创建数据框"&gt;创建数据框&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kids &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Jack&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Jill&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ages &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;d &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data.frame&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kids, ages,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stringsAsFactors&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;FALSE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(d)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; kids ages
1 Jack 12
2 Jill 10
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;stringsAsFactors&lt;/code&gt; 参数用于将字符串转换为因子 (factor)，默认值为 TRUE。&lt;/p&gt;
&lt;h3 id="访问数据框"&gt;访问数据框&lt;/h3&gt;
&lt;p&gt;数据框是一个列表，可以通过索引或者组件名访问&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(d[[1]])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;Jack&amp;#34; &amp;#34;Jill&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(d&lt;span style="color:#f92672"&gt;$&lt;/span&gt;kids)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;Jack&amp;#34; &amp;#34;Jill&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以使用类似矩阵的方式&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(d[, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;Jack&amp;#34; &amp;#34;Jill&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;str()&lt;/code&gt; 函数查看数据框&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;str&lt;/span&gt;(d)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;#39;data.frame&amp;#39;:	2 obs. of 2 variables:
 $ kids: chr &amp;#34;Jack&amp;#34; &amp;#34;Jill&amp;#34;
 $ ages: num 12 10
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="扩展案例考试成绩的回归分析续"&gt;扩展案例：考试成绩的回归分析（续）&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;score &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read.csv&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/student-mat.csv&amp;#34;&lt;/span&gt;, header&lt;span style="color:#f92672"&gt;=&lt;/span&gt;T)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;head&lt;/span&gt;(score)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/r/study/dataframe/score-head.png"&gt;
&lt;/figure&gt;

&lt;h2 id="其他矩阵式操作"&gt;其他矩阵式操作&lt;/h2&gt;
&lt;p&gt;矩阵操作可以应用到数据框中&lt;/p&gt;</description></item><item><title>Meteva笔记：计算站点降水的检验指标</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-27-meteva-notebook-station-rain-indices/</link><pubDate>Sun, 27 Sep 2020 16:11:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-27-meteva-notebook-station-rain-indices/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Meteva 是由 nmc 开源的全流程检验程序库，提供了常用的各种气象预报检验评估的算法函数，气象检验分析的图片和表格型产品的制作函数，以及检验评估系统示例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文以 24 小时累积降水为例，说明如何根据二分类预报列联表计算常用检验指标。
同时会介绍如何使用 &lt;a href="https://github.com/nmcdev/meteva"&gt;Meteva&lt;/a&gt; 中的函数进行计算。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;使用上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-27-meteva-notebook-station-rain-table/"&gt;Meteva笔记：计算站点降水的检验指标 - 列联表&lt;/a&gt;》中计算的列联表。&lt;/p&gt;
&lt;p&gt;以 10 mm 降水为例说明二分式 (dichotomous, yes/no) 预测的检验指标&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_10 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df_matrix[df_matrix[&lt;span style="color:#e6db74"&gt;&amp;#34;threshold&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_10
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/verify/meteva/station/index/df-10.png"&gt;
&lt;/figure&gt;

&lt;p&gt;总数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df_10[[&lt;span style="color:#e6db74"&gt;&amp;#34;hits&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;false_alarms&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;misses&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;correct_negatives&amp;#34;&lt;/span&gt;]]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sum()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;2361
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同时会将计算结果与 Meteva 进行对比。&lt;/p&gt;
&lt;p&gt;为了结果一致性，从 Meteva 计算的结果中减去 2 个样本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hfmc_10_orig &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hfmcs[&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hfmc_10_orig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([[1801, 176, 1977],
 [ 242, 144, 386],
 [2043, 320, 2363]])
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hfmc_10_mod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hfmc_10_orig &lt;span style="color:#f92672"&gt;-&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;array(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hfmc_10_mod
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([[1799, 176, 1975],
 [ 242, 144, 386],
 [2041, 320, 2361]])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;meteva.method&lt;/code&gt; 中的方法使用 4 个元素的数组表示列联表&lt;/p&gt;</description></item><item><title>Meteva笔记：计算站点降水的检验指标 - 列联表</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-27-meteva-notebook-station-rain-table/</link><pubDate>Sun, 27 Sep 2020 15:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-27-meteva-notebook-station-rain-table/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Meteva 是由 nmc 开源的全流程检验程序库，提供了常用的各种气象预报检验评估的算法函数，气象检验分析的图片和表格型产品的制作函数，以及检验评估系统示例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文以 24 小时累积降水为例，说明如何根据站点观测计算二分类预报的列联表，为后续计算检验指标提供基础数据。
同时会介绍如何使用 &lt;a href="https://github.com/nmcdev/meteva"&gt;Meteva&lt;/a&gt; 根据站点观测表格数据计算列联表。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;载入需要使用的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; geopandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; gpd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; shapely.geometry &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Polygon
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参数"&gt;参数&lt;/h2&gt;
&lt;p&gt;区域范围，仅计算区域内的观测&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;145&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;降水阈值，单位为 mm。为每个阈值分别计算列联表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thresholds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;观测时刻，2020 年 8 月 1 日 00 时次&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_date &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-08-01 00:00:00&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择 12 时次预报&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_start_hour &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;数据目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_root &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/g2/nwp_vfy/operation/EC&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;h3 id="观测数据"&gt;观测数据&lt;/h3&gt;
&lt;p&gt;使用《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-20-meteva-notebook-load-local-obs-file/"&gt;Meteva笔记：加载本地观测数据&lt;/a&gt;》中介绍的观测数据。
nwpc-data 库已内置该数据的路径。&lt;/p&gt;</description></item><item><title>AMS机器学习课程：Keras深度学习 - 卷积神经网络</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-25-ams-ml-python-keras-cnn/</link><pubDate>Fri, 25 Sep 2020 22:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-25-ams-ml-python-keras-cnn/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;David John Gagne, 2019: &amp;ldquo;Deep Learning with Keras&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_3/ML_Short_Course_Module_3_Deep_Learning.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_3/ML_Short_Course_Module_3_Deep_Learning.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;David John Gagne, National Center for Atmospheric Research&lt;/p&gt;
&lt;p&gt;本文接上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-22-ams-ml-python-keras-ann/"&gt;AMS机器学习课程：Keras深度学习 - 人工神经网络&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;为卷积神经网络，我们将加载以每次风暴为中心的空间块 (spatial patches)。&lt;/p&gt;
&lt;p&gt;本文数据的下载方法请查阅《&lt;a href="https://blog.perillaroc.wang/post/2020/07/2020-07-26-ams-ml-python-course-data-analysis-and-preproc/"&gt;AMS机器学习课程：数据分析与预处理&lt;/a&gt;》&lt;/p&gt;
&lt;h3 id="准备"&gt;准备&lt;/h3&gt;
&lt;p&gt;载入需要使用的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; tqdm.notebook &lt;span style="color:#f92672"&gt;import&lt;/span&gt; tqdm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="路径"&gt;路径&lt;/h3&gt;
&lt;p&gt;创建风暴 netCDF4 文件的列表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;start_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pathlib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Path(&lt;span style="color:#e6db74"&gt;&amp;#34;../data/track_data_ncar_ams_3km_nc_small&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;storm_files &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sorted(start_path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;glob(&lt;span style="color:#e6db74"&gt;&amp;#34;*.nc&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;storm_files[:&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[WindowsPath(&amp;#39;../data/track_data_ncar_ams_3km_nc_small/NCARSTORM_20101024-0000_d01_model_patches.nc&amp;#39;),
 WindowsPath(&amp;#39;../data/track_data_ncar_ams_3km_nc_small/NCARSTORM_20101122-0000_d01_model_patches.nc&amp;#39;),
 WindowsPath(&amp;#39;../data/track_data_ncar_ams_3km_nc_small/NCARSTORM_20110201-0000_d01_model_patches.nc&amp;#39;),
 WindowsPath(&amp;#39;../data/track_data_ncar_ams_3km_nc_small/NCARSTORM_20110308-0000_d01_model_patches.nc&amp;#39;),
 WindowsPath(&amp;#39;../data/track_data_ncar_ams_3km_nc_small/NCARSTORM_20110326-0000_d01_model_patches.nc&amp;#39;)]
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="定义问题"&gt;定义问题&lt;/h3&gt;
&lt;p&gt;输入变量&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;input_vars &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;REFL_COM_curr&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;U10_curr&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;V10_curr&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出变量&lt;/p&gt;</description></item><item><title>学习R语言：列表</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-23-study-r-list/</link><pubDate>Wed, 23 Sep 2020 21:53:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-23-study-r-list/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;列表在 R 中扮演着一个至关重要的角色，是数据框 (&lt;code&gt;data.frame&lt;/code&gt;) 和面向对象编程的基础。&lt;/p&gt;
&lt;h2 id="创建列表"&gt;创建列表&lt;/h2&gt;
&lt;p&gt;列表属于“递归型” (recursive) 向量。&lt;/p&gt;
&lt;p&gt;创建一个列表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;j &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Joe&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; salary&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;55000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; union&lt;span style="color:#f92672"&gt;=&lt;/span&gt;T
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打印列表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(j)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;$name
[1] &amp;#34;Joe&amp;#34;

$salary
[1] 55000

$union
[1] TRUE
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;R 语言中列表各组件的名称叫做 &lt;strong&gt;标签&lt;/strong&gt; (tags)。&lt;/p&gt;
&lt;p&gt;标签是可选的，不指定标签会自动生成默认标签。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jalt &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Joe&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55000&lt;/span&gt;, T)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(jalt)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[[1]]
[1] &amp;#34;Joe&amp;#34;

[[2]]
[1] 55000

[[3]]
[1] TRUE
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用标签访问列表组件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(j&lt;span style="color:#f92672"&gt;$&lt;/span&gt;name)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;Joe&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因为列表也是向量，所以可以使用 &lt;code&gt;vector()&lt;/code&gt; 创建列表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vector&lt;/span&gt;(mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;list&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;z[[&lt;span style="color:#e6db74"&gt;&amp;#34;abc&amp;#34;&lt;/span&gt;]] &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(z)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;$abc
[1] 3
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="列表的常规操作"&gt;列表的常规操作&lt;/h2&gt;
&lt;h3 id="列表索引"&gt;列表索引&lt;/h3&gt;
&lt;p&gt;有多种方式访问列表组件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(j&lt;span style="color:#f92672"&gt;$&lt;/span&gt;salary)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 55000
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(j[[&lt;span style="color:#e6db74"&gt;&amp;#34;salary&amp;#34;&lt;/span&gt;]])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 55000
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(j[[2]])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 55000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上述三种方式返回列表 lst 中的组件 c，返回值是 c 的数据类型：&lt;/p&gt;</description></item><item><title>AMS机器学习课程：Keras深度学习 - 人工神经网络</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-22-ams-ml-python-keras-ann/</link><pubDate>Tue, 22 Sep 2020 20:15:23 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-22-ams-ml-python-keras-ann/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;David John Gagne, 2019: &amp;ldquo;Deep Learning with Keras&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_3/ML_Short_Course_Module_3_Deep_Learning.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_3/ML_Short_Course_Module_3_Deep_Learning.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;David John Gagne, National Center for Atmospheric Research&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;h3 id="目标"&gt;目标&lt;/h3&gt;
&lt;p&gt;了解深度学习的定义及其与传统机器学习方法的区别&lt;/p&gt;
&lt;p&gt;了解 Keras 是什么，它如何工作以及如何与其他深度学习库交互&lt;/p&gt;
&lt;p&gt;在 Keras 中建立一个全连接神经网络&lt;/p&gt;
&lt;p&gt;了解激活函数的选择如何影响性能&lt;/p&gt;
&lt;p&gt;在 Keras 中建立卷积神经网络，并与全连接神经网络比较，看看它的性能如何&lt;/p&gt;
&lt;p&gt;了解数据是如何通过卷积层转换的&lt;/p&gt;
&lt;h3 id="软件需求"&gt;软件需求&lt;/h3&gt;
&lt;p&gt;本节使用如下的软件库&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.6 或更高版本&lt;/li&gt;
&lt;li&gt;Numpy&lt;/li&gt;
&lt;li&gt;Pandas&lt;/li&gt;
&lt;li&gt;Matplotlib&lt;/li&gt;
&lt;li&gt;IPython&lt;/li&gt;
&lt;li&gt;Jupyter&lt;/li&gt;
&lt;li&gt;Xarray&lt;/li&gt;
&lt;li&gt;netCDF4&lt;/li&gt;
&lt;li&gt;Tensorflow (为训练卷积神经网络，推荐使用 GPU 版本)&lt;/li&gt;
&lt;li&gt;Keras&lt;/li&gt;
&lt;li&gt;CUDA 9.2 或更高版本和 cuDNN (用于与 NVIDIA GPU 接口)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="什么是深度学习"&gt;什么是深度学习&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/03/01/ai_ml_dl_diagram.png"&gt;
&lt;/figure&gt;

&lt;p&gt;深度学习应在人工智能和机器学习的背景下进行定义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;人工智能 (Artificial Intelligence, AI)&lt;/strong&gt;：计算机执行传统上由人类完成的认知任务而无需人类直接控制的多种方式。&lt;/p&gt;
&lt;p&gt;从历史上看，开发人工智能系统有两种思想流派。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;专家系统 (Expert Systems)&lt;/strong&gt;：任务专家创建描述任务完成方式的算法和规则，然后 AI 程序根据规则完成任务。&lt;/p&gt;</description></item><item><title>Meteva笔记：加载本地观测数据</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-20-meteva-notebook-load-local-obs-file/</link><pubDate>Sun, 20 Sep 2020 19:38:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-20-meteva-notebook-load-local-obs-file/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Meteva 是由 nmc 开源的全流程检验程序库，提供了常用的各种气象预报检验评估的算法函数，气象检验分析的图片和表格型产品的制作函数，以及检验评估系统示例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何将 NWPC 生成的站点观测文本文件接入到 &lt;a href="https://github.com/nmcdev/meteva"&gt;Meteva&lt;/a&gt; 工具中。&lt;/p&gt;
&lt;h2 id="站点数据格式"&gt;站点数据格式&lt;/h2&gt;
&lt;p&gt;在 Meteva 中，使用 &lt;code&gt;pandas.DataFrame&lt;/code&gt; 对象表示站点数据，类似 Excel 表格。&lt;/p&gt;
&lt;p&gt;每个站点数据表格都必须包含如下所示的六个列，用于表示每行记录的元信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;level&lt;/code&gt;：层次&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time&lt;/code&gt;：时间&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dtime&lt;/code&gt;：预报时效&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt;：站点号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lon&lt;/code&gt;：站点经度&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lat&lt;/code&gt;：站点纬度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其余列均为数据列，可以任意取名字。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;加载需要使用到的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;meteva.base&lt;/code&gt; 提供 IO、数据处理和绘图函数，&lt;code&gt;meteva.method&lt;/code&gt; 提供检验指标计算函数，&lt;code&gt;meteva.product&lt;/code&gt; 提供集成的诊断函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; meteva.base &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; meb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; meteva.method &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; mem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; meteva.product &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; mpd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="gds-数据"&gt;GDS 数据&lt;/h2&gt;
&lt;p&gt;首先从 GDS 服务中加载观测资料&lt;/p&gt;
&lt;p&gt;读取 IP 地址和端口号&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gds_config_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/g1/u/wangdp/.config/.nmcdev/config.ini&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip, port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; meb&lt;span style="color:#f92672"&gt;.&lt;/span&gt;io&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_gds_ip_port(gds_config_file)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="读取观测资料"&gt;读取观测资料&lt;/h3&gt;
&lt;p&gt;GDS 数据路径，读取 2020 年 9 月 19 日 08 时的全国地面站观测资料&lt;/p&gt;</description></item><item><title>Meteva笔记：加载GRIB 2要素场</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-18-meteva-notebook-load-grib2-field/</link><pubDate>Fri, 18 Sep 2020 16:58:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-18-meteva-notebook-load-grib2-field/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Meteva 是由 nmc 开源的全流程检验程序库，提供了常用的各种气象预报检验评估的算法函数，气象检验分析的图片和表格型产品的制作函数，以及检验评估系统示例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何通过 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 库将本地 GRIB 2 文件接入到 &lt;a href="https://github.com/nmcdev/meteva"&gt;Meteva&lt;/a&gt; 工具中。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;本文代码均在 CMA-PI 高性能计算机上运行。&lt;/p&gt;
&lt;p&gt;载入需要的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; meteva.base &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; meb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; meteva.method &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; mem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;meb&lt;/code&gt; 提供 IO 和绘图相关函数，&lt;code&gt;mem&lt;/code&gt; 提供计算检验指标的函数。&lt;/p&gt;
&lt;h2 id="从-gds-加载数据"&gt;从 GDS 加载数据&lt;/h2&gt;
&lt;p&gt;在加载本地数据文件前，首先使用 Meteva 内置的函数从 GDS 服务中获取要素场，用于后续对比验证。&lt;/p&gt;
&lt;p&gt;GDS 服务的相关配置方法请访问同样由 nmcdev 开源的 &lt;a href="https://github.com/nmcdev/nmc_met_io"&gt;nmcdev/nmc_met_io&lt;/a&gt; 项目。&lt;/p&gt;
&lt;p&gt;Meteva 支持 nmc_met_io 项目的配置文件。
本文使用已配置好的文件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gds_config_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/g1/u/USER/.config/.nmcdev/config.ini&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;meb.io.read_gds_ip_port&lt;/code&gt; 从配置文件中读取 IP 地址和端口号&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ip, port &lt;span style="color:#f92672"&gt;=&lt;/span&gt; meb&lt;span style="color:#f92672"&gt;.&lt;/span&gt;io&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_gds_ip_port(gds_config_file)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="格点数据"&gt;格点数据&lt;/h3&gt;
&lt;p&gt;加载 GRAPES GFS 的格点数据。&lt;/p&gt;</description></item><item><title>ISLR实验：R语言简介</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-17-islr-lab-r-introduction/</link><pubDate>Thu, 17 Sep 2020 20:38:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-17-islr-lab-r-introduction/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源自《统计学习导论：基于R语言应用》(ISLR) 中《2.3 实验：R语言简介》章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;注：本文在 Jupyter Notebook 中运行，为了正常显示，绝大部分语句都添加了 &lt;code&gt;print()&lt;/code&gt; 函数。如果在命令行交互模式下执行，则无需 &lt;code&gt;print()&lt;/code&gt; 函数。&lt;/p&gt;
&lt;h2 id="基本命令"&gt;基本命令&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;c()&lt;/code&gt; 函数创建向量，&lt;code&gt;&amp;lt;-&lt;/code&gt; 进行赋值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 1 3 2 5
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;也可以使用 &lt;code&gt;=&lt;/code&gt; 进行赋值，但不推荐&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 1 6 2
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;length()&lt;/code&gt; 函数获取向量长度&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(x))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 3
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(y))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;向量加法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 2 10 5
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ls()&lt;/code&gt; 函数查看所有的对象列表。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rm()&lt;/code&gt; 函数可以删除不需要的对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ls&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] &amp;#34;x&amp;#34; &amp;#34;y&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;rm&lt;/span&gt;(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ls&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;character(0)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;删除所有对象&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;rm&lt;/span&gt;(list&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ls&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;matrix()&lt;/code&gt; 函数创建矩阵&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matrix&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nrow&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ncol&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1] [,2]
[1,] 1 3
[2,] 2 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以省略参数名称&lt;/p&gt;</description></item><item><title>关于模式检验系列文章的说明</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-17-notes-on-verification-posts/</link><pubDate>Thu, 17 Sep 2020 17:05:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-17-notes-on-verification-posts/</guid><description>&lt;p&gt;之前写了几篇关于模式检验方法的文章，可能会引起一些误会，在此我说明下写这些文章的初衷。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;我不应该提及尚在内部开发中的工具，在此我郑重道歉：抱歉没能很好地区分工作项目与业余项目，未来会多加注意。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="为什么想学习模式检验"&gt;为什么想学习模式检验&lt;/h2&gt;
&lt;p&gt;对于非科班出身的气象从业者，尤其对于日常工作是数值预报业务系统运维的我来说，想要进一步了解数值预报模式的核心技术，最可行的方式就是从模式流程的前后两端入手。
也就是从资料预处理，产品制作和检验评估等方面入手。
其他诸如资料同化，模式积分等方面由于涉及大量领域知识，很难在缺乏系统训练的情况下入门。&lt;/p&gt;
&lt;p&gt;近期一直在关注气象领域的机器学习方法，看到验证模型性能用到的部分指标实际上就来自模式检验，已在下面几篇翻译文章中有所介绍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-17-ams-ml-python-basic-ml-binarization-roc/"&gt;预测雷暴旋转的基础机器学习：分类 - ROC 曲线&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-19-ams-ml-python-basic-ml-binarization-performance-diagram/"&gt;预测雷暴旋转的基础机器学习：分类 - 性能图&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-20-ams-ml-python-basic-ml-binarization-attributes-diagram/"&gt;预测雷暴旋转的基础机器学习：分类 - 属性图&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;机器学习和模式检验都会使用到统计学中很多概念。
今年我在模式运行维护方面的一些工作也逐步向统计学靠拢，已在下面几篇文章中有所介绍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-11-analytic-nwp-production-file-created-time/"&gt;统计数值天气预报模式产品生成的典型时间&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time-bootstrapping/"&gt;统计数值预报产品生成时间：单个时效重采样&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-01-analytic-nwp-production-file-created-time-multi-bootstrap/"&gt;统计数值预报产品生成时间：重采样&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最近也正在看统计学相关的书籍（虽然进展很慢），例如《面向数据科学家的实用统计学》。&lt;/p&gt;
&lt;p&gt;模式检验作为数值预报系统的重要部分，是学习统计学时很好的实战应用，所以我在近期开始尝试了解模式检验相关的知识。&lt;/p&gt;
&lt;h2 id="为什么要写代码"&gt;为什么要写代码&lt;/h2&gt;
&lt;p&gt;想掌握一门技术，必须要动手练习。对于程序员来说，最好的练习就是写程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感谢开发 GetPy 的前辈老师，提供方便易用的工具，包括输入数据、计算方法和图形绘制等全套流程。&lt;/strong&gt;
让我可以从代码开始学习模式检验的相关知识，也节省大量用于准备数据的时间。&lt;/p&gt;
&lt;p&gt;之前我写的几篇公众号文章中大量列出代码，&lt;strong&gt;绝不是&lt;/strong&gt; GetPy 中的代码，&lt;strong&gt;也不是&lt;/strong&gt; 对现有工具的源码解析，&lt;strong&gt;更不是&lt;/strong&gt; 为了与现有工具做对比。&lt;/p&gt;
&lt;p&gt;这些代码仅是按照从代码中学到的检验算法由我个人编写的代码，纯粹用于学习性质，&lt;strong&gt;绝不是&lt;/strong&gt; 以构建检验工具为目的而编写，也没有任何的通用性。&lt;/p&gt;
&lt;p&gt;虽然我在文章中提到 GetPy，但我仅是工具包的 &lt;strong&gt;使用者&lt;/strong&gt;，并时刻准备为工具包的开发贡献力量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我更关注如何实现已有的算法，而不是去研究新的算法或指标。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="后续该如何继续学习"&gt;后续该如何继续学习&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;为了避免引起更多误会，我已将公众号上已发表的检验相关文章全部删除。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;后续我依然会学习检验指标和算法，但会将参考项目换为由 nmc 开源的检验工具包 &lt;a href="https://github.com/nmcdev/meteva"&gt;meteva&lt;/a&gt;。
该工具包提供详细的说明文档，包括对各类检验指标的介绍，并提供丰富的图形产品。&lt;/p&gt;
&lt;p&gt;前面之所以没有由该工具开始，就是因为缺乏现成的输入数据。
不过既然数据预处理往往是各类数据分析系统最关键、最耗时间的一个环节，还是应该尝试从零开始，由原始数据生成分析算法需要的输入数据。&lt;/p&gt;
&lt;p&gt;虽然很多工具开源的目的就是为了避免大家重复造轮子而浪费时间精力，但我始终认为重复造轮子是一种很好的学习方式。
有了对照，才能更清晰地掌握自己学习的效果究竟如何。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;最后，我还是要郑重声明：本公众号仅代表个人观点，所用数据无法代表真实情况。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>学习 R 语言：矩阵和数组</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-16-study-r-matrix-and-array/</link><pubDate>Wed, 16 Sep 2020 19:53:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-16-study-r-matrix-and-array/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;矩阵 (Matrix) 是一种特殊的向量，包含两个附加属性：行数和列数。&lt;/p&gt;
&lt;p&gt;数组 (Array) 是更一般的对象，可以有多个维度。矩阵是二维数组。&lt;/p&gt;
&lt;h2 id="创建矩阵"&gt;创建矩阵&lt;/h2&gt;
&lt;p&gt;R 中下标从 1 开始，矩阵按列存储。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;matrix()&lt;/code&gt; 函数创建矩阵&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matrix&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nrow&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ncol&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1] [,2]
[1,] 1 3
[2,] 2 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在给定所有元素的情况下，&lt;code&gt;nrow&lt;/code&gt; 和 &lt;code&gt;ncol&lt;/code&gt; 两个参数只需要给出一个&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matrix&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nrow&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1] [,2]
[1,] 1 3
[2,] 2 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;另一种方法是创建空的矩阵，再对每一位赋值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matrix&lt;/span&gt;(nrow&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, ncol&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1] [,2]
[1,] NA NA
[2,] NA NA
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y[1, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y[2, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y[1, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y[2, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;] &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(y)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [,1] [,2]
[1,] 1 3
[2,] 2 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;设置参数 &lt;code&gt;byrow=TRUE&lt;/code&gt;，可以按行提供的矩阵数据。
但矩阵实际还是按列存储&lt;/p&gt;</description></item><item><title>计算站点降水的检验指标：列联表</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-15-verification-station-rain-basic-indices-table/</link><pubDate>Tue, 15 Sep 2020 21:19:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-15-verification-station-rain-basic-indices-table/</guid><description>&lt;p&gt;本文以 24 小时累积降水为例，说明如何根据站点观测计算二分类预报的列联表，为后续计算检验指标提供基础数据。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重要提示：本文使用的数据均来自其他工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;载入需要使用到的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; geopandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; gpd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; shapely.geometry &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Polygon
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参数"&gt;参数&lt;/h2&gt;
&lt;p&gt;区域范围，仅计算区域内的观测&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;145&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;降水阈值，单位为 mm。为每个阈值分别计算列联表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;thresholds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;数据目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_root &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/base/run_grapes/ECMWF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;obs_rain_root &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/base/run_grapes/obsrain&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;观测时刻，2020 年 8 月 1 日 00 时次&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_date &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-08-01 00:00:00&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择 12 时次预报&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_start_hour &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仅计算 036 时效的 24 小时累积降水&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;current_forecast_hour &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; current_start_hour
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;h3 id="观测数据"&gt;观测数据&lt;/h3&gt;
&lt;p&gt;已从 GTS 数据中提取的降水数据，忽略 24 小时降水为缺失值的条目。&lt;/p&gt;</description></item><item><title>学习 R 语言：向量</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-13-study-r-vector/</link><pubDate>Sun, 13 Sep 2020 20:55:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-13-study-r-vector/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;R 语言最基本的数据类型是向量&lt;/p&gt;
&lt;p&gt;本节会关注以下话题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;循环补齐&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;筛选&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量化&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文代码运行在 Jupyter Notebook 中，所以使用 &lt;code&gt;print&lt;/code&gt; 函数输出变量；如果直接在命令行交互环境中运行，则无需使用 &lt;code&gt;print&lt;/code&gt; 函数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="标量向量数组与矩阵"&gt;标量、向量、数组与矩阵&lt;/h2&gt;
&lt;p&gt;R 语言中变量类型被称为模式 (mode)。
同一向量中的所有元素必须是相同的模式。&lt;/p&gt;
&lt;h3 id="添加或删除向量元素"&gt;添加或删除向量元素&lt;/h3&gt;
&lt;p&gt;R 语言中向量是连续存储的，不能插入或删除数据。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：类似 C++ 中的 &lt;code&gt;std::array&lt;/code&gt;，在创建时就已经确定数组大小，后续无法修改大小&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;插入和删除数据实际上是对变量重新赋值&lt;/p&gt;
&lt;p&gt;注：插入删除数据会生成新的向量&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;88&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(x[1&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;], &lt;span style="color:#ae81ff"&gt;168&lt;/span&gt;, x[4])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 88 5 12 168 13
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注：可以将 x 看成类似 C 语言中的指针&lt;/p&gt;
&lt;h3 id="获取向量长度"&gt;获取向量长度&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;length()&lt;/code&gt; 函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(x))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;获取第一个 1 所在位置的索引（不一定有效率）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;first1 &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(x) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt;(x)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (x[i] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;(i)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;first1&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;R 语言中，&lt;code&gt;1:n&lt;/code&gt; 返回从 1 到 n 的向量，类似 Python 中的 &lt;code&gt;range&lt;/code&gt; 函数。&lt;/p&gt;</description></item><item><title>使用 xarray 合并 GRIB 2 要素场</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-11-combine-grib2-fields-using-xarray/</link><pubDate>Fri, 11 Sep 2020 20:59:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-11-combine-grib2-fields-using-xarray/</guid><description>&lt;p&gt;本文介绍如何合并使用 &lt;code&gt;xarray.DataArray&lt;/code&gt; 表示的 GRIB 2 要素场。&lt;/p&gt;
&lt;p&gt;主要用于解决如下问题：&lt;/p&gt;
&lt;p&gt;已有表示为 &lt;code&gt;xarray.DataArray&lt;/code&gt; 的三维数据，维度是：时间，纬度和经度。
如何增加一个纬度，用于表示预报时效。&lt;/p&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;xarray 数据包含坐标 (&lt;code&gt;coords&lt;/code&gt;) 和维度 (&lt;code&gt;dims&lt;/code&gt;)，其中维度是数据实际的维数，维度均包含在坐标中；但坐标可以是非维度坐标，用于提供对数据的附加描述。&lt;/p&gt;
&lt;p&gt;例如，使用 nwpc-data 加载某个 GRIB 2 要素场，返回的 &lt;code&gt;xr.DataArray&lt;/code&gt; 对象类似下面的截图：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/data/nwpc-data/xarray/combine/field.png"&gt;
&lt;/figure&gt;

&lt;p&gt;可以看到在单个要素场中仅有经纬度 (&lt;code&gt;latitude&lt;/code&gt;, &lt;code&gt;longitude&lt;/code&gt;) 两个坐标是维度，其余坐标 (&lt;code&gt;time&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;, &lt;code&gt;valid_time&lt;/code&gt; 和 &lt;code&gt;pl&lt;/code&gt;) 均不是维度坐标。
也就是说，返回的要素场是二维的。&lt;/p&gt;
&lt;p&gt;如果需要增加的维度已在数据的坐标对象 &lt;code&gt;coords&lt;/code&gt; 中，则可以使用 &lt;code&gt;expand_dims&lt;/code&gt; 方法将其转为维度坐标，再使用 &lt;code&gt;xr.concat&lt;/code&gt; 函数沿某个维度合并多个数据。&lt;/p&gt;
&lt;p&gt;本文首先介绍如何实现开头提出的问题，即在时间，纬度和经度三个维度基础上增加预报时效维度。
最后介绍 &lt;code&gt;nwpc-data&lt;/code&gt; 库中提供的类似功能。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;本文使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 库从 GRIB 2 文件中加载要素场。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_field_from_file,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_field_from_files,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="单个要素场"&gt;单个要素场&lt;/h2&gt;
&lt;p&gt;以单个要素场为例，说明如何对 nwpc-data 库加载的 GRIB 2 消息进行处理。&lt;/p&gt;</description></item><item><title>计算地面要素场基本检验指标</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-10-verification-surface-level-basic-indices/</link><pubDate>Thu, 10 Sep 2020 21:00:20 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-10-verification-surface-level-basic-indices/</guid><description>&lt;p&gt;本文以 2 米温度为例，说明如何根据站点观测计算地面要素场的检验指标。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重要提示：本文使用的数据均来自其他工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;载入需要使用到的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; geopandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; gpd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;计算检验指标最关键的步骤就是准备数据。&lt;/p&gt;
&lt;p&gt;本文仅使用下面子区域中的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;domain &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;55&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;70&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;145&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="观测数据"&gt;观测数据&lt;/h3&gt;
&lt;p&gt;使用现有的观测数据，每个时次一个文件。&lt;/p&gt;
&lt;p&gt;原始观测数据来自从 CIMISS 检索的全球地面逐小时数据 (SURF_GLB_MUL_HOR)。&lt;/p&gt;
&lt;p&gt;下面是一个时次的样例文件&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;2016070112 08652
61902 -7.97 345.60 1019.20 26.60 17.90 150.00 8.20 999999.00 999999.00 999999.00 999999.00
10147 53.63 9.99 1011.90 18.70 15.98 210.00 6.30 0.10 0.10 999999.00 1010.10
10162 53.64 11.39 1012.30 22.10 14.95 210.00 6.60 0.00 0.00 999999.00 1005.40
10184 54.10 13.41 1013.20 24.20 12.68 230.00 4.50 0.00 0.00 999999.00 1012.40
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;第一行是时次和条目数。&lt;/p&gt;</description></item><item><title>学习 R 语言：快速开始</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-08-study-r-quickstart/</link><pubDate>Tue, 08 Sep 2020 16:44:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-08-study-r-quickstart/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文内容来自《R 语言编程艺术》(The Art of R Programming)，有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="运行r"&gt;运行R&lt;/h2&gt;
&lt;h3 id="交互模式"&gt;交互模式&lt;/h3&gt;
&lt;p&gt;使用命令行运行 &lt;code&gt;R.exe&lt;/code&gt; (linux 中运行 &lt;code&gt;R&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;本文示例均在 Jupyter Lab 中运行 R 环境&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：在 Jupyter Notebook 中，只有使用 &lt;code&gt;print&lt;/code&gt; 函数才能正确输出序号值，
直接执行变量名输出的结果没有序号，与 R 命令行交互环境中不同&lt;/p&gt;
&lt;p&gt;下面代码为了展示输出结果均为向量，均使用 &lt;code&gt;print&lt;/code&gt; 函数打印。
如果直接在交互环境中运行，则不需要添加 &lt;code&gt;print&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;mean&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;abs&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;[1] 0.7482577
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;print&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; [1] 0.03721293 -0.20435474 -0.19896266 -0.81638471 2.38975757 -0.13099913
 [7] -1.69019026 1.04377265 0.83753176 -1.41777840
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="批处理模式"&gt;批处理模式&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-r" data-lang="r"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pdf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;xh.pdf&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;hist&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;rnorm&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dev.off&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;R.exe CMD BATCH z.R
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="r-会话"&gt;R 会话&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;注：从本节开始，代码中省略 print 函数调用，与命令行交互模式保持一致&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="向量"&gt;向量&lt;/h3&gt;
&lt;p&gt;R 语言中最基本的数据类型是向量&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;-&lt;/code&gt; 是 R 语言的标准赋值运算符&lt;/p&gt;</description></item><item><title>等压面要素场检验指标绘图</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-04-verification-pressure-level-basic-indices-plot/</link><pubDate>Fri, 04 Sep 2020 23:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-04-verification-pressure-level-basic-indices-plot/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-02-verification-pressure-level-basic-indices-parallel/"&gt;计算等压面要素场检验指标 - 并发&lt;/a&gt;》及之前的几篇文章介绍如何计算等压面要素场的检验指标。&lt;/p&gt;
&lt;p&gt;本文介绍如何用计算得到的检验指标绘图。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;检验指标数据保存在 CSV 文件中，如下图所示&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;forecast_hour,variable,level,region,rmse,me,mae,sd,rmsem,rmsep,acc
0,gh,1000,NHEM,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,1.000000
0,gh,1000,SHEM,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,1.000000
...
24,t,10,GLOB,1.020141,-0.155320,0.794115,1.008247,0.155320,0.864821,0.963317
...
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;载入使用的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; tqdm.auto &lt;span style="color:#f92672"&gt;import&lt;/span&gt; tqdm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="读取单个文件"&gt;读取单个文件&lt;/h2&gt;
&lt;p&gt;检验指标文件按照不同的预报时间保存到 CSV 文件中&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;./stats.2018072512.csv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;pd.read_csv&lt;/code&gt; 函数载入 CSV 文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_csv(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/verify/getpy/plev/stats-plot/read-csv-head.png"&gt;
&lt;/figure&gt;

&lt;p&gt;处理缺失值，数据中的 &lt;code&gt;-999.0&lt;/code&gt; 代表缺失值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table[table &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;999.0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;nan
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;添加日期作为新列 (&lt;code&gt;date&lt;/code&gt;)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table[&lt;span style="color:#e6db74"&gt;&amp;#34;date&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2018-07-25 12:00:00&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置多级索引&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;table&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_index(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;date&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;variable&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;level&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;region&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/verify/getpy/plev/stats-plot/multi-index-head.png"&gt;
&lt;/figure&gt;

&lt;p&gt;将读取单个文件的代码封装成函数 &lt;code&gt;read_stats&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;read_stats&lt;/span&gt;(file_path: str) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pathlib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Path(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exists():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stats.%Y%m&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%H.csv&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_csv(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table[table &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;999.0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;nan
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table[&lt;span style="color:#e6db74"&gt;&amp;#34;date&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(current_time)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table &lt;span style="color:#f92672"&gt;=&lt;/span&gt; table&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_index(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;date&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;variable&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;level&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;region&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; table
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="读取多个文件"&gt;读取多个文件&lt;/h2&gt;
&lt;p&gt;构造时间序列&lt;/p&gt;</description></item><item><title>计算等压面要素场检验指标 - 并发</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-02-verification-pressure-level-basic-indices-parallel/</link><pubDate>Wed, 02 Sep 2020 23:29:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-02-verification-pressure-level-basic-indices-parallel/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-01-verification-pressure-level-basic-indices-multi-forecast-hours/"&gt;计算等压面要素场检验指标 - 多时效&lt;/a&gt;》中介绍如何批量计算等压面要素多个时次多时效的检验指标。&lt;/p&gt;
&lt;p&gt;本文进一步讨论批量计算的耗时，关注计算效率问题。&lt;/p&gt;
&lt;h2 id="计算分析"&gt;计算分析&lt;/h2&gt;
&lt;p&gt;在《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-01-verification-pressure-level-basic-indices-multi-forecast-hours/"&gt;多时效&lt;/a&gt;》的“计算”章节中，笔者使用 5 层 &lt;code&gt;for&lt;/code&gt; 循环，逐个为每个要素场计算检验指标。&lt;/p&gt;
&lt;p&gt;下图展示了计算的层次，并将部分耗时较长的代码封装成函数。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/verify/getpy/plev/stats-multi-dask/plev-stats-multi-flow.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;等压面要素场检验指标批量计算层次&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;get_values&lt;/code&gt; 函数用于从 GRIB 2 文件中载入需要的要素场。
对于每个要素场，需要从三个不同的文件中分别加载预报场 (&lt;code&gt;F&lt;/code&gt;)，分析场 (&lt;code&gt;A&lt;/code&gt;) 和气候场 (&lt;code&gt;C&lt;/code&gt;)。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;get_stats&lt;/code&gt; 函数计算并返回一组检验指标。
每个要素场 (由 &lt;code&gt;start_hours&lt;/code&gt;，&lt;code&gt;forecast_hours&lt;/code&gt;，&lt;code&gt;parameters&lt;/code&gt; 和 &lt;code&gt;levels&lt;/code&gt; 决定) 计算多个区域 (&lt;code&gt;regions&lt;/code&gt;)。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;get_total_df&lt;/code&gt; 函数将多组的检验指标合并。
每个时间点 (&lt;code&gt;start_hours&lt;/code&gt;) 执行一次。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;save_df&lt;/code&gt; 将某天对应的所有检验指标写入到 CSV 文件中。
每个时间点 (&lt;code&gt;start_hours&lt;/code&gt;) 执行一次。&lt;/p&gt;
&lt;h2 id="串行耗时"&gt;串行耗时&lt;/h2&gt;
&lt;p&gt;使用《&lt;a href="https://blog.perillaroc.wang/post/2020/09/2020-09-01-verification-pressure-level-basic-indices-multi-forecast-hours/"&gt;多时效&lt;/a&gt;》文中的示例数据，串行执行上述过程，不包含 &lt;code&gt;save_df&lt;/code&gt;，在 Jupyter Notebook 中使用 &lt;code&gt;%%time&lt;/code&gt; 统计耗时如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;CPU times: user 20min 28s, sys: 1min 29s, total: 21min 57s
Wall time: 22min 22s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;即计算一个月数据的指标用时超过 20 分钟，显然耗时太长。
可以使用并发方式加快计算过程。&lt;/p&gt;</description></item><item><title>计算等压面要素场检验指标 - 多时效</title><link>https://blog.perillaroc.wang/post/2020/09/2020-09-01-verification-pressure-level-basic-indices-multi-forecast-hours/</link><pubDate>Tue, 01 Sep 2020 20:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/09/2020-09-01-verification-pressure-level-basic-indices-multi-forecast-hours/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-28-verification-forecast-against-analyses-basic-indices-fore-pressure-level-example/"&gt;使用 xarray 计算单个要素场的基本检验指标&lt;/a&gt;》介绍为单个时次的单个时效的等压面要素场计算检验指标。&lt;/p&gt;
&lt;p&gt;本文继续介绍如何为多个时次的多个时效计算检验指标，并将其汇总成表格形式，方便进行持久化保存。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;导入需要的包&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; eccodes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data_tool.verify.data &lt;span style="color:#f92672"&gt;import&lt;/span&gt; get_message
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data_tool.verify.plev.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; calculate_plev_stats
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 库封装 eccodes 的函数 &lt;code&gt;nwpc_data.grib.eccodes.load_message_from_file&lt;/code&gt; 加载要素场。&lt;/p&gt;
&lt;p&gt;之前介绍的检验指标计算已整合到 &lt;a href="https://github.com/perillaroc/nwpc-data-tool"&gt;nwpc-data-tool&lt;/a&gt; 库中。
调用 &lt;code&gt;calculate_plev_stats&lt;/code&gt; 函数会返回包含指标的 &lt;code&gt;pandas.DataFrame&lt;/code&gt; 对象。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;重要提示：本文数据来自其他工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;某个试验的数据目录，包含 2016 年 7 月 1 日至 7 月 31 日的预报结果&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_root_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/some/path/to/CTL/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;analysis_root_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/some/path/to/CTL/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;climate_root_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/some/path/to/obdata/cmean&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参数"&gt;参数&lt;/h2&gt;
&lt;p&gt;预报时效&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_hours &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;193&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_hours
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([ 0, 24, 48, 72, 96, 120, 144, 168, 192])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要素名称&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 决策树集成学习</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-31-ams-ml-python-basic-ml-binarization-decision-tree-ensemble/</link><pubDate>Mon, 31 Aug 2020 20:51:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-31-ams-ml-python-basic-ml-binarization-decision-tree-ensemble/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-30-ams-ml-python-basic-ml-binarization-decision-tree-super-parameter/"&gt;预测雷暴旋转的基础机器学习：分类 - 决策树超参数试验&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用随机森林 (Random Forest) 和梯度提升决策树 (Gradient Boosted Decision Trees, GBDT) 降低决策树的过拟合现象。&lt;/p&gt;
&lt;h2 id="随机森林"&gt;随机森林&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;随机森林 (Random Forest) 是决策树的集合。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在介绍决策树的第一个示例中，您可能已经注意到很多 &lt;strong&gt;过拟合 (overfitting)&lt;/strong&gt; 的情况。
这通常是决策树的问题，因为它们依赖于精确的阈值，这会在决策函数中引入“跳跃”。&lt;/p&gt;
&lt;p&gt;例如，在下面显示的树中，CAPE 的差异为 0.0001 J kg^-1 可能导致龙卷风概率的差异为 55％。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/11/tree_schematic.jpg"&gt;
&lt;/figure&gt;

&lt;p&gt;减轻这种过拟合的一种方法是：训练一堆决策树。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果决策树足够多样化，则它们有望具有抵消的偏差&lt;/strong&gt;（以不同方式过拟合）。&lt;/p&gt;
&lt;p&gt;随机森林以两种方式确保多样性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example-bagging&lt;/li&gt;
&lt;li&gt;Predictor-bagging (or &amp;ldquo;feature-bagging&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;example-bagging&lt;/strong&gt; 通过使用训练数据的 &lt;strong&gt;自助副本 (bootstrapped replicate)&lt;/strong&gt; 训练每棵树来完成。&lt;/p&gt;
&lt;p&gt;对于带有 N 个示例的训练集，通过随机抽样替换 N 个示例来创建“自助复制”。
替换采样会导致重复。
平均而言，每个自助复制都仅包含 63.2％ (1 - e^{-1}) 的唯一示例，其他 37.8％ 是重复的。
这样可以确保使用不同的独特示例集对每棵树进行训练。&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 决策树超参数试验</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-30-ams-ml-python-basic-ml-binarization-decision-tree-super-parameter/</link><pubDate>Sun, 30 Aug 2020 22:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-30-ams-ml-python-basic-ml-binarization-decision-tree-super-parameter/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-29-ams-ml-python-basic-ml-binarization-decision-tree/"&gt;预测雷暴旋转的基础机器学习：分类 - 决策树&lt;/a&gt;》，介绍如何通过超参数试验确定决策树的最小样本量。&lt;/p&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;两个超参数（以及其他）控制决策树的深度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个分支节点的最小样本量 (N_{b}^{min})&lt;/li&gt;
&lt;li&gt;每个叶节点的最小样本量 (N_{l}^{min})&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果将这些值设置为 1，则树可能会变得很深，从而增加其过拟合的能力。&lt;/p&gt;
&lt;p&gt;您可以用另一种方式思考：如果每个叶节点上只有一个示例，则所有预测都将仅基于一个示例，并且可能无法很好地推广到新数据。&lt;/p&gt;
&lt;p&gt;相反，如果将 N_{b}^{min} 和 N_{l}^{min} 设置得过高，则树将变得不够深，从而导致树欠拟合。&lt;/p&gt;
&lt;p&gt;例如，假设有 1000 个训练样本并将 N_{l}^{min} 设置为 1000。
这将只允许一个分支节点（根节点）。
根节点的两个子节点都具有 &amp;lt;1000 个示例。
因此，预测将仅基于一个问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回顾超参数试验的四个步骤&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选择要尝试的值&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们尝试&lt;/p&gt;
&lt;p&gt;\begin{equation*}
N_b^{\textrm{min}} \in \lbrace 2, 5, 10, 20, 30, 40, 50, 100, 200, 500 \rbrace
\end{equation*}&lt;/p&gt;
&lt;p&gt;和&lt;/p&gt;
&lt;p&gt;\begin{equation*}
N_l^{\textrm{min}} \in \lbrace 1, 5, 10, 20, 30, 40, 50, 100, 200, 500 \rbrace
\end{equation*}&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 决策树</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-29-ams-ml-python-basic-ml-binarization-decision-tree/</link><pubDate>Sat, 29 Aug 2020 12:42:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-29-ams-ml-python-basic-ml-binarization-decision-tree/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;使用《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-16-ams-ml-python-course-basic-ml-binarization-train/"&gt;预测雷暴旋转的基础机器学习：分类 - 训练&lt;/a&gt;》文章中处理过的数据。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;决策树是具有&lt;strong&gt;分支节点&lt;/strong&gt;（椭圆）和&lt;strong&gt;叶节点&lt;/strong&gt;（矩形）的流程图。
在下图中，f 是恶劣天气的预测概率。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/11/decision-tree.jpg"&gt;
&lt;/figure&gt;

&lt;p&gt;分支节点是分叉的，叶节点是终端的。
换句话说，每个分支节点有2个子节点，每个叶节点有0个子节点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在叶节点进行预测，并在分支节点提出问题。&lt;/strong&gt;
由于分支节点是分支的，因此&lt;strong&gt;在分支节点处提出的问题必须能用是或否回答。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;自 1960 年代以来 (Chisholm 1968)，决策树已用于气象学。
它们是由人类专家主观构建的，直到 1980 年代，当时开发了一种目标算法 (Quinlan 1986) 来“训练”它们（确定每个分支节点的最佳问题）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;叶节点 L 的预测值是到达该节点 L 的所有训练样本的平均值。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于回归，这是一个真实值（达到 L 的示例的平均未来最大涡度）。&lt;/li&gt;
&lt;li&gt;对于分类，这是一个概率（达到 L 的样本中最大未来涡 &amp;gt;= 3.850×10^{-3} s^{-1} 的比例）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;strong&gt;每个分支节点选择的问题是使信息增益 (information gain) 最大化的问题。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这是通过最小化 &amp;ldquo;remainder&amp;rdquo; 来完成的&lt;/strong&gt;，&amp;ldquo;remainder&amp;rdquo; 基于子节点的熵。&lt;/p&gt;
&lt;p&gt;一个节点的信息熵 (information entropy) 定义如下。&lt;/p&gt;</description></item><item><title>使用 xarray 计算单个要素场的基本检验指标</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-28-verification-forecast-against-analyses-basic-indices-fore-pressure-level-example/</link><pubDate>Fri, 28 Aug 2020 16:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-28-verification-forecast-against-analyses-basic-indices-fore-pressure-level-example/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-25-verification-forecast-against-analyses-basic-indices-for-pressure-level/"&gt;计算等压面要素场的基本检验指标&lt;/a&gt;》中介绍了基本检验指标的计算函数。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用这些函数，在 xarray 数组上计算要素场的基本检验指标。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;等压面要素场的统计指标，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mean Error&lt;/li&gt;
&lt;li&gt;Mean Absolute Error&lt;/li&gt;
&lt;li&gt;Standard Deviation&lt;/li&gt;
&lt;li&gt;RMSE&lt;/li&gt;
&lt;li&gt;RMSEm&lt;/li&gt;
&lt;li&gt;RMSEp&lt;/li&gt;
&lt;li&gt;ACC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文以某次试验的 2018-08-01 12时次 24 时效的 1000hPa 温度场为例说明如何计算单个要素场的基本统计指标。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;重要提示：本文数据来自其他工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文使用的数据均以 GRIB 1 格式保存，且已被插值到 1.5 度 * 1.5 度的经纬度网格。&lt;/p&gt;
&lt;p&gt;本文将模式预报 000 时效的数据当成分析场。所以只涉及两类数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模式预报数据：文件名是 &lt;code&gt;pgbfFFF.graeps.YYYYMMDDHH&lt;/code&gt;，其中 &lt;code&gt;FFF&lt;/code&gt; 是预报时效，&lt;code&gt;YYYYMMDDHH&lt;/code&gt; 是起报时次&lt;/li&gt;
&lt;li&gt;气候数据：文件名是 &lt;code&gt;cmean_1d.1959MMDD&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;导入需要的软件包&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pathlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置数据目录，使用模式本身的 000 时效作为分析场。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;forecast_root_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/some/path/to/ctrl1/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;analysis_root_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/some/path/to/ctrl1/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;climate_root_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/some/path/to/obdata/cmean&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置通用参数&lt;/p&gt;</description></item><item><title>计算等压面要素场的基本检验指标</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-25-verification-forecast-against-analyses-basic-indices-for-pressure-level/</link><pubDate>Wed, 26 Aug 2020 22:55:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-25-verification-forecast-against-analyses-basic-indices-for-pressure-level/</guid><description>&lt;p&gt;本文介绍计算等压面要素场的几种基本检验指标。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重要提示：本文介绍的部分代码参考自其他检验工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;本文介绍的基本检验指标涉及以下三种数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预报场 (forecast_field)&lt;/li&gt;
&lt;li&gt;分析场 (analysis_field)：当前模式的分析场或者使用 FNL 等其他分析场&lt;/li&gt;
&lt;li&gt;气候场 (climate_field)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文假定上述数据均被插值成 WMO GDPFS 手册中规定的标准网格，即 1.5 度 * 1.5 度。
下面的指标计算不涉及数据插值问题。&lt;/p&gt;
&lt;p&gt;计算指标还需要使用到网格点对应的纬度坐标值 (latitudes) 。&lt;/p&gt;
&lt;p&gt;指标计算即可以针对全球范围，也可以针对特定的区域范围。
本文假定上述四个参数都已按照选定的区域范围进行裁剪。&lt;/p&gt;
&lt;h2 id="指标"&gt;指标&lt;/h2&gt;
&lt;h3 id="mean-error"&gt;Mean Error&lt;/h3&gt;
&lt;p&gt;Mean Error (ME)，也叫作 Bias，表示预报值与验证值之间的偏差的平均值。
定义如下：&lt;/p&gt;
&lt;p&gt;\begin{align*}
\textrm{ME} &amp;amp;\equiv \left ( \sum_{i=1}^{n}w_iD_i \right ) \mathbin{/} \sum_{i=1}^{n}w_i \
\end{align*}&lt;/p&gt;
&lt;p&gt;\begin{align*}
D_i &amp;amp;= F_i - A_i \
\end{align*}&lt;/p&gt;
&lt;p&gt;\begin{align*}
w_i &amp;amp;= \frac{1}{n} (\text{or } \cos\phi_i \text{, and so on})
\end{align*}&lt;/p&gt;
&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F_i 表示预报值&lt;/li&gt;
&lt;li&gt;A_i 表示验证值 (verification value)&lt;/li&gt;
&lt;li&gt;D_i 表示两者的差值&lt;/li&gt;
&lt;li&gt;w_i 是权重系数，n 是样本的个数，phi_i 是纬度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;观测值，初始值或客观分析值通常被用作验证值。
当预报完全正确时，ME 等于 0，被称为完美预报 (perfect forecast)。&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 系数与正则化</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-22-ams-ml-python-basic-ml-binarization-regularization/</link><pubDate>Sat, 22 Aug 2020 22:26:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-22-ams-ml-python-basic-ml-binarization-regularization/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-21-ams-ml-python-basic-ml-binarization-eval/"&gt;预测雷暴旋转的基础机器学习：分类 - 评估&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="系数"&gt;系数&lt;/h2&gt;
&lt;p&gt;下一个单元为逻辑回归模型绘制系数。&lt;/p&gt;
&lt;p&gt;正（负）系数意味着概率随着预测变量的增加（减小）。&lt;/p&gt;
&lt;p&gt;同样，将预测变量归一化为相同的标度 (z-scores)，因此通常具有较大系数的预测变量更为重要。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;plot_model_coefficients&lt;/code&gt; 函数绘制模型系数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;plot_model_coefficients&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; model, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; predictor_names
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; coefficients &lt;span style="color:#f92672"&gt;=&lt;/span&gt; model&lt;span style="color:#f92672"&gt;.&lt;/span&gt;coef_
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num_dimensions &lt;span style="color:#f92672"&gt;=&lt;/span&gt; len(coefficients&lt;span style="color:#f92672"&gt;.&lt;/span&gt;shape)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; num_dimensions &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; coefficients &lt;span style="color:#f92672"&gt;=&lt;/span&gt; coefficients[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#f92672"&gt;...&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num_predictors &lt;span style="color:#f92672"&gt;=&lt;/span&gt; len(predictor_names)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y_coords &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;linspace(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, num_predictors &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num&lt;span style="color:#f92672"&gt;=&lt;/span&gt;num_predictors, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dtype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;float
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _, axes_object &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;subplots(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; axes_object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;barh(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y_coords, coefficients, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;array([&lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;158&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;119&lt;/span&gt;], dtype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;float) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; edgecolor&lt;span style="color:#f92672"&gt;=&lt;/span&gt;np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;array([&lt;span style="color:#ae81ff"&gt;27&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;158&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;119&lt;/span&gt;], dtype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;float) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; linewidth&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;xlabel(&lt;span style="color:#e6db74"&gt;&amp;#39;Coefficient&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ylabel(&lt;span style="color:#e6db74"&gt;&amp;#39;Predictor variable&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;yticks([], [])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_tick_values, _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;xticks()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;xticks(x_tick_values, rotation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;90&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_min &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;percentile(coefficients, &lt;span style="color:#ae81ff"&gt;1.&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_max &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;percentile(coefficients, &lt;span style="color:#ae81ff"&gt;99.&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pyplot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;xlim([x_min, x_max])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; j &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(num_predictors):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; axes_object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;text(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, y_coords[j], predictor_names[j], 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;array([&lt;span style="color:#ae81ff"&gt;217&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;95&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;], dtype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;float) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; horizontalalignment&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;center&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; verticalalignment&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;center&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fontsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;绘制逻辑回归模型的系数&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 评估</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-21-ams-ml-python-basic-ml-binarization-eval/</link><pubDate>Fri, 21 Aug 2020 22:29:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-21-ams-ml-python-basic-ml-binarization-eval/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-20-ams-ml-python-basic-ml-binarization-attributes-diagram/"&gt;预测雷暴旋转的基础机器学习：分类 - 属性图&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;本文在前面三篇介绍评估图形的文章基础上评估示例分类问题。&lt;/p&gt;
&lt;h2 id="评估"&gt;评估&lt;/h2&gt;
&lt;p&gt;评估训练集&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;training_probabilities &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plain_log_model&lt;span style="color:#f92672"&gt;.&lt;/span&gt;predict_proba(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; training_predictor_table&lt;span style="color:#f92672"&gt;.&lt;/span&gt;values
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)[:, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;training_event_frequency &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mean(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; training_target_table[BINARIZED_TARGET_NAME]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;values
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eval_binary_classifn(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; observed_labels&lt;span style="color:#f92672"&gt;=&lt;/span&gt;training_target_table[BINARIZED_TARGET_NAME]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;values,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_probabilities&lt;span style="color:#f92672"&gt;=&lt;/span&gt;training_probabilities,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; training_event_frequency&lt;span style="color:#f92672"&gt;=&lt;/span&gt;training_event_frequency,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dataset_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;training&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Training Max Peirce score (POD - POFD) = 0.639
Training AUC (area under ROC curve) = 0.897
Training Max CSI (critical success index) = 0.375
Training Brier score = 0.064
Training Brier skill score (improvement over climatology) = 0.293
&lt;/code&gt;&lt;/pre&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/09/training-roc.png"&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/09/training-performance.png"&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/09/training-attributes.png"&gt;
&lt;/figure&gt;

&lt;p&gt;评估验证集&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 属性图</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-20-ams-ml-python-basic-ml-binarization-attributes-diagram/</link><pubDate>Thu, 20 Aug 2020 23:17:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-20-ams-ml-python-basic-ml-binarization-attributes-diagram/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章，介绍如何绘制属性图 (Attributes diagram) 评估二元分类问题。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-19-ams-ml-python-basic-ml-binarization-performance-diagram/"&gt;预测雷暴旋转的基础机器学习：分类 - 性能图&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;训练数据集上的 Attributes Diagram&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/08/attributes-diagram-training.png"&gt;
&lt;/figure&gt;

&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;引自 &lt;a href="https://www.cawcr.gov.au/projects/verification/"&gt;https://www.cawcr.gov.au/projects/verification/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;概率预测给出事件发生的概率 (probability)，其值在 0 到 1（或 0 到 100％）之间。
通常，很难验证单个概率预测。
取而代之的是，使用观察到那些事件已发生 (oi=1) 或未发生 (oi=0) 的概率来验证一组概率预测 pi。&lt;/p&gt;
&lt;p&gt;准确的概率预测系统具有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reliability: 预测概率与平均观测频率之间的一致性&lt;/li&gt;
&lt;li&gt;sharpness: 预测概率接近于 0 或 1 的趋势，而不是围绕均值聚集的值&lt;/li&gt;
&lt;li&gt;resolution: 预测将样本事件集分解为具有特征不同结果的子集的能力&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="reliability-diagram"&gt;Reliability diagram&lt;/h3&gt;
&lt;p&gt;当包含代表气候态的 no-resolution 和 no-skill 线时被称为“attributes diagram”。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/08/ReliabilityDiagram.gif"&gt;
&lt;/figure&gt;

&lt;p&gt;可靠性图绘制了观测频率 (observed frequency) 与预测概率 (forecast probability) 的关系图，其中预测概率的范围分为 K 个区间（例如 0-5％，5-15％，15-25％等）。
每个数据仓中的样本大小通常以直方图或数据点旁边的值的形式包含在内。&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 性能图</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-19-ams-ml-python-basic-ml-binarization-performance-diagram/</link><pubDate>Wed, 19 Aug 2020 23:45:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-19-ams-ml-python-basic-ml-binarization-performance-diagram/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章，介绍如何绘制性能图 (Performance diagram) 评估二元分类问题。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-17-ams-ml-python-basic-ml-binarization-roc/"&gt;预测雷暴旋转的基础机器学习：分类 - ROC 曲线&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="性能图"&gt;性能图&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;引自&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cawcr.gov.au/projects/verification"&gt;https://www.cawcr.gov.au/projects/verification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cawcr.gov.au/projects/verification/Roebber/PerformanceDiagram.html"&gt;https://www.cawcr.gov.au/projects/verification/Roebber/PerformanceDiagram.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Performance Diagram&lt;/p&gt;
&lt;p&gt;验证数据集上的性能图如下所示&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/07/performance-training.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="混淆矩阵"&gt;混淆矩阵&lt;/h3&gt;
&lt;p&gt;二分类问题的混淆矩阵&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/07/contingency-table.png" alt=""&gt;&lt;/p&gt;
&lt;h3 id="pod"&gt;POD&lt;/h3&gt;
&lt;p&gt;真阳率&lt;/p&gt;
&lt;p&gt;Probability of detection (hit rate)，POD&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/07/pod.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回答如下问题&lt;/strong&gt;：有多少观察到&amp;quot;是&amp;quot;的事件被正确预测？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;范围&lt;/strong&gt;：0 到 1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完美分数&lt;/strong&gt;：1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特性&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;对 hits (TP) 敏感，但忽略 false alarm (FP)。
对事件的气候频率非常敏感。
适用于罕见事件。
可以通过发布更多“是”预测来增加 hits 次数，从而人为地加以改进。
应与 false alarm ratio 结合使用。
POD 还是广泛用于概率预测的Relative Operating Characteristic (ROC) 的重要组成部分。&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - ROC 曲线</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-17-ams-ml-python-basic-ml-binarization-roc/</link><pubDate>Mon, 17 Aug 2020 22:17:03 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-17-ams-ml-python-basic-ml-binarization-roc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章，介绍如何绘制 ROC 曲线评估二元分类问题。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-16-ams-ml-python-course-basic-ml-binarization-train/"&gt;预测雷暴旋转的基础机器学习：分类 - 训练&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="评估性能"&gt;评估性能&lt;/h2&gt;
&lt;p&gt;utils 包中的 &lt;code&gt;eval_binary_classifn&lt;/code&gt; 函数用于评估二元分类模型的性能，绘制三类图形。&lt;/p&gt;
&lt;p&gt;本文介绍 ROC 曲线的绘制，下图是训练数据集的 ROC 曲线。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/06/training-roc.png"&gt;
&lt;/figure&gt;

&lt;h2 id="roc-曲线"&gt;ROC 曲线&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;以下部分引自:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《机器学习》（周志华）&lt;/li&gt;
&lt;li&gt;维基百科“ROC曲线”条目 &lt;a href="https://zh.wikipedia.org/wiki/ROC%E6%9B%B2%E7%BA%BF"&gt;https://zh.wikipedia.org/wiki/ROC%E6%9B%B2%E7%BA%BF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cawcr.gov.au/projects/verification/"&gt;https://www.cawcr.gov.au/projects/verification/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;二分类问题分类结果的混淆矩阵 Confusion Matrix&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/05/confusion-matrix.png"&gt;
&lt;/figure&gt;

&lt;p&gt;查准率 Precision&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/05/precision.png"&gt;
&lt;/figure&gt;

&lt;p&gt;查全率 Recall 或 真正例率 Ture Positive Rate (TPR)。
在所有实际为阳性的样本中，被&lt;strong&gt;正确地&lt;/strong&gt;判断为阳性之比率。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/05/recall-v2.png"&gt;
&lt;/figure&gt;

&lt;p&gt;假正例率 False Positive Rate (FPR)。
在所有实际为阴性的样本中，被&lt;strong&gt;错误地&lt;/strong&gt;判断为阳性之比率。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ams-ml-python/02/05/false-positive-rate.png"&gt;
&lt;/figure&gt;

&lt;p&gt;类似本文使用的逻辑回归模型，很多学习器是为测试样本产生一个实值或概率预测，然后将这个预测值与一个分类阈值(threshold)进行比较，若大于阈值则分类为正类，否则为反类。&lt;/p&gt;
&lt;p&gt;在逻辑回归模型中，模型输出的结果是样本为正类的概率([0, 1])。&lt;/p&gt;</description></item><item><title>预测雷暴旋转的基础机器学习：分类 - 训练</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-16-ams-ml-python-course-basic-ml-binarization-train/</link><pubDate>Sun, 16 Aug 2020 11:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-16-ams-ml-python-course-basic-ml-binarization-train/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从本文开始，将介绍二元分类问题。&lt;/p&gt;
&lt;h2 id="示例数据"&gt;示例数据&lt;/h2&gt;
&lt;p&gt;关于本文示例数据的详细信息，请参考之前介绍线性回归的系列文章：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-03-ams-ml-python-course-basic-ml-data/"&gt;预测雷暴旋转的基础机器学习 - 数据&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="二元分类"&gt;二元分类&lt;/h2&gt;
&lt;p&gt;本模块的其余部分着重于二元分类，而不是回归。
“回归”是对实数的预测（例如，上面我们预测了最大未来涡度）。
“分类”是对类别的预测（例如，低，中或高最大未来涡度）。&lt;/p&gt;
&lt;p&gt;在二元分类中，有两个类别。
因此，预测采取回答 &lt;strong&gt;是或否问题&lt;/strong&gt; 的形式。
除了将其二值化外，我们将使用相同的目标变量（最大未来涡度）。
问题将是预测最大未来涡度是否超过阈值。&lt;/p&gt;
&lt;h2 id="二值化"&gt;二值化&lt;/h2&gt;
&lt;p&gt;下一个单元格将目标变量“二值化”（将每个值转换为 0 或 1，是或否）。&lt;/p&gt;
&lt;p&gt;阈值是所有训练示例中最大未来涡度的 90％。&lt;/p&gt;
&lt;p&gt;使用相同的阈值对训练，验证和测试数据进行二值化。&lt;/p&gt;
&lt;h3 id="使用的函数"&gt;使用的函数&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;get_binarization_threshold&lt;/code&gt; 用于计算阈值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_binarization_threshold&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; csv_file_names, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; percentile_level: float,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; float:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_target_values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;array([])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; tqdm(range(len(csv_file_names))):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; this_file_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; csv_file_names[i]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# print(f&amp;#39;Reading data from: &amp;#34;{this_file_name}&amp;#34;...&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; this_target_table &lt;span style="color:#f92672"&gt;=&lt;/span&gt; read_feature_file(this_file_name)[&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_target_values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;concatenate((
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_target_values, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; this_target_table[TARGET_NAME]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;values
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; binarization_threshold &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;percentile(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_target_values, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; percentile_level
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;Binarization threshold for &amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;TARGET_NAME&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;binarization_threshold&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.4e&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; binarization_threshold
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;示例&lt;/p&gt;</description></item><item><title>AMS机器学习课程：预测雷暴旋转的基础机器学习 - 超参数试验</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-08-ams-ml-python-course-basic-ml-super-parameter/</link><pubDate>Sat, 08 Aug 2020 21:18:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-08-ams-ml-python-course-basic-ml-super-parameter/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-08-ams-ml-python-course-basic-ml-regularization/"&gt;AMS机器学习课程：预测雷暴旋转的基础机器学习 - 正则化&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="l1-和-l2-正则化的超参数试验"&gt;L1 和 L2 正则化的超参数试验&lt;/h2&gt;
&lt;p&gt;接下来的几个单元格将向您展示如何进行“超参数实验”。
&lt;strong&gt;超参数实验的步骤如下。&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;选择要尝试的值。&lt;/strong&gt; 这通常基于对模型如何工作的一些先验知识。
您拥有的专业知识越多，可以尝试的值范围就越窄。在这种情况下，我们尝试&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;\begin{equation*}
\lambda_1 \in \lbrace 10^{-8}, 10^{-7.5}, 10^{-7}, 10^{-6.5}, 10^{-6}, 10^{-5.5}, 10^{-5}, 10^{-4.5}, 10^{-4} \rbrace
\end{equation*}&lt;/p&gt;
&lt;p&gt;和&lt;/p&gt;
&lt;p&gt;\begin{equation*}
\lambda_2 \in \lbrace 10^{-4}, 10^{-3.5}, 10^{-3}, 10^{-2.5}, 10^{-2}, 10^{-1.5}, 10^{-1}, 10^{-0.5}, 10^{0}, 10^{0.5}, 10^{1} \rbrace
\end{equation*}&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;使用每种超参数组合训练模型。&lt;/strong&gt; 在这种情况下，lambda_{1} 有9个值，lambda_{2} 有 11 个值，因此有 99 个组合。这称为“网格搜索（grid search）”。
（注意：除了网格搜索，还有其他搜索方法。这些方法特别有用，特别是当组合的数量太大（“组合爆炸”）时，如果您尝试的是几个以上的超参数，通常会发生这种情况。在这种情况下，您可以进行 random search 或 beam search，使用遗传算法来进化超参数，等等。但是在此模块中，我们将坚持使用网格搜索。）&lt;/p&gt;</description></item><item><title>AMS机器学习课程：预测雷暴旋转的基础机器学习 - 正则化</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-08-ams-ml-python-course-basic-ml-regularization/</link><pubDate>Sat, 08 Aug 2020 18:28:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-08-ams-ml-python-course-basic-ml-regularization/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-06-ams-ml-python-course-basic-ml-linear-regression/"&gt;AMS机器学习课程：预测雷暴旋转的基础机器学习 - 线性回归&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="l1-和-l2-正则化"&gt;L1 和 L2 正则化&lt;/h2&gt;
&lt;p&gt;概括地说，正则化是通过创建更简单的模型来防止过拟合的一种方法。
L1 和 L2 正则鼓励模型具有较小的系数。&lt;/p&gt;
&lt;p&gt;当有许多预测因素时，这很有用，因为其中一些预测因素可能与现象之间的因果关系较弱。
如果不进行正则化，模型将尝试合并每个预测变量，这可能导致训练数据的特殊性过拟合。
正则化鼓励模型只为少量预测变量（&lt;strong&gt;真正&lt;/strong&gt;重要的预测变量）学习大系数。&lt;/p&gt;
&lt;p&gt;L1 和 L2 正则化通过向损失函数添加惩罚来鼓励较小的系数。&lt;/p&gt;
&lt;p&gt;对于线性回归，损耗函数如下：&lt;/p&gt;
&lt;p&gt;\begin{equation*}
\epsilon = \frac{1}{N} \sum\limits_{i = 1}^{N} (\hat{y}&lt;em&gt;i - y_i)^2 + \lambda_1 \sum\limits&lt;/em&gt;{j = 1}^{M} \lvert \beta_j \rvert + \lambda_2 \sum\limits_{j = 1}^{M} \beta_j^2 = \textrm{MSE} + \lambda_1 \sum\limits_{j = 1}^{M} \lvert \beta_j \rvert + \lambda_2 \sum\limits_{j = 1}^{M} \beta_j^2
\end{equation*}&lt;/p&gt;</description></item><item><title>AMS机器学习课程：预测雷暴旋转的基础机器学习 - 线性回归</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-06-ams-ml-python-course-basic-ml-linear-regression/</link><pubDate>Fri, 07 Aug 2020 00:10:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-06-ams-ml-python-course-basic-ml-linear-regression/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文接上一篇文章&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/08/2020-08-03-ams-ml-python-course-basic-ml-data/"&gt;AMS机器学习课程：预测雷暴旋转的基础机器学习 - 数据&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="线性回归"&gt;线性回归&lt;/h2&gt;
&lt;p&gt;线性回归将以下方程与训练数据拟合&lt;/p&gt;
&lt;p&gt;$$
\hat{y} = \beta_0 + \sum\limits_{j = 1}^{M} \beta_j x_j
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;x_j 是第 j 个预测变量&lt;/li&gt;
&lt;li&gt;beta_j 是第 j 个预测变量的系数，在训练过程中会被调整&lt;/li&gt;
&lt;li&gt;M 是预测变量的数目&lt;/li&gt;
&lt;li&gt;beta_0 是偏置系数或截距，在训练过程中会被调整&lt;/li&gt;
&lt;li&gt;hat{y} 是对目标变量的预测，在本例中，是未来风暴中最大的涡度，单位是每秒&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;权重（beta_0 和 beta_j）经过训练以使均方误差（Mean Squared Error，MSE）最小。
这也是为什么线性回归会被称为“最小二乘线性回归”。&lt;/p&gt;
&lt;p&gt;\begin{equation*}
\textrm{MSE} = \frac{1}{N} \sum\limits_{i = 1}^{N} (\hat{y}_i - y_i)^2
\end{equation*}&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;y_i 是第 i 个样本的实际目标值。在本例中，一个示例是一次一个风暴单元，或者一个“风暴对象”&lt;/li&gt;
&lt;li&gt;hat{y_i} 是第 i 个样本的预测目标值&lt;/li&gt;
&lt;li&gt;N 是训练样本的数量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将上面两个等值合并可以得到下面的等式，其中 x_{ij} 是第 j 个预测变量的第 i 个样本&lt;/p&gt;</description></item><item><title>视界：用于可扩展后处理的 Hermes 服务</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-05-view-the-hermes-service-for-scalable-post-processing/</link><pubDate>Wed, 05 Aug 2020 15:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-05-view-the-hermes-service-for-scalable-post-processing/</guid><description>&lt;blockquote&gt;
&lt;p&gt;最近验收的某个工程项目使用到了气象大数据云平台的加工流水线制作图形产品。
为了对比产品后处理方面国内外的发展现状，重新温习下这篇由 ECMWF 发表于 2017 年的文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 153 - Autumn 2017 中 Florian Rathgeber，Tiago Quintino 和 Baudouin Raoult 的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/153/news/hermes-service-scalable-post-processing"&gt;The Hermes service for scalable post-processing&lt;/a&gt;》，版权归原作者所有。&lt;/p&gt;
&lt;p&gt;翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;ECMWF 已经开发了一种可扩展的后处理分布式计算服务，称为 Hermes。
这项新服务将使计算更接近数据，从而支持 ECMWF 的可伸缩计划（ECMWF’s Scalability Programme），从而节省了带宽并减少了对客户端处理能力的需求。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：Hermes 是希腊神话中的诸神传令的使者。参见 &lt;a href="https://zh.wikipedia.org/wiki/%E8%B5%AB%E8%80%B3%E5%A2%A8%E6%96%AF"&gt;Wikipedia 词条&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="动机"&gt;动机&lt;/h3&gt;
&lt;p&gt;30多年来，用户一直在从 ECMWF 的气象归档和检索系统（Meteorological Archiving and Retrieval System，MARS）请求数据。
内部用户可以通过命令行客户端访问 MARS，该客户端将从存档中提取数据到用户的工作站，并在本地执行任何请求的后处理。
另一方面，外部用户经常使用 MARS Web API，此时后处理是在为 ECMWF 的 Web 基础结构提供服务的一台计算机上进行的，处理过的数据通过 HTTP 发送给用户。&lt;/p&gt;
&lt;p&gt;随着分辨率的提高以及集合预报的战略重要性，将整个要素场转移到客户端以进行后处理可能会占用大量空间并浪费带宽，尤其是在长时间序列的数据中仅提取一个小区域或单个点的情况下。
由于客户端可能没有必要的处理能力或后处理可能花费太长时间，因此需要对后处理执行的位置进行更多控制。&lt;/p&gt;
&lt;p&gt;ECMWF 于 2014 年启动的可伸缩性计划认识到需要使计算更接近数据。
作为该计划的一部分，Hermes 项目开发了一种分布式计算服务，以在使用类似体系结构的同时扩充 MARS。
Hermes 使用新的插值包 MIR，专注于后处理领域。
该项目的成功完成意味着 Hermes 软件包可以成为 ECMWF 未来数据处理系统开发的一部分。&lt;/p&gt;</description></item><item><title>AMS机器学习课程：预测雷暴旋转的基础机器学习 - 数据</title><link>https://blog.perillaroc.wang/post/2020/08/2020-08-03-ams-ml-python-course-basic-ml-data/</link><pubDate>Mon, 03 Aug 2020 21:32:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/08/2020-08-03-ams-ml-python-course-basic-ml-data/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;.
&lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;该模块使用基本的机器学习模型 ———— 线性回归，逻辑回归，决策树，随机森林和梯度增强树 ———— 来预测来自 NCAR convection-allowing ensemble 的数值模拟中未来的雷暴旋转（Schwartz &lt;em&gt;et al.&lt;/em&gt; 2015）。&lt;/p&gt;
&lt;p&gt;请按以下方式引用笔记本。&lt;/p&gt;
&lt;p&gt;Lagerquist, R., and D.J. Gagne II, 2019: &amp;ldquo;Basic machine learning for predicting thunderstorm rotation: Python tutorial&amp;rdquo;. &lt;a href="https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb"&gt;https://github.com/djgagne/ams-ml-python-course/blob/master/module_2/ML_Short_Course_Module_2_Basic.ipynb&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文使用的数据需要额外下载，请浏览《&lt;a href="https://blog.perillaroc.wang/post/2020/07/2020-07-26-ams-ml-python-course-data-analysis-and-preproc/"&gt;AMS机器学习课程：数据分析与预处理&lt;/a&gt;》获取更多信息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参考文献"&gt;参考文献&lt;/h2&gt;
&lt;p&gt;本笔记本引用了下面列出的一些出版物。&lt;/p&gt;
&lt;p&gt;Chisholm, D., J. Ball, K. Veigas, and P. Luty, 1968: &amp;ldquo;The diagnosis of upper-level humidity.&amp;rdquo; &lt;em&gt;Journal of Applied Meteorology&lt;/em&gt;, &lt;strong&gt;7 (4)&lt;/strong&gt;, 613-619.&lt;/p&gt;</description></item><item><title>气象大数据云平台培训感想</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-30-thoughts-about-cmadaas-training/</link><pubDate>Fri, 31 Jul 2020 00:34:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-30-thoughts-about-cmadaas-training/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文仅代表作者在文章发布时的个人观点，不排除未来会有所改变&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天在领导的要求下几乎全程参加了信息中心关于气象大数据云平台的在线培训。&lt;/p&gt;
&lt;p&gt;即使领导没有明确要求，我也还是想听听与气象大数据云平台相关的培训。
毕竟气象大数据云平台即将于今年业务化，作为近几年气象局在气象信息化领域最重要的布局，所有业务系统都不免要与其打交道。&lt;/p&gt;
&lt;h2 id="现行计划"&gt;现行计划&lt;/h2&gt;
&lt;p&gt;按照目前的规划，数值预报业务系统将在明年开始启动融入气象大数据云平台的进程。
最终的融入方案尚未确定，但已确定实施的路线。
计划从产品后处理入手，并过渡到资料前处理等步骤。
最终将所有非并行计算的任务都迁移到云平台中，而高性能计算机上仅保留并行计算任务。&lt;/p&gt;
&lt;p&gt;下图是我个人对现行融入计划的理解：今年（2020年）保持现有业务系统不变；明年（即2021年）将图片产品制作迁移到云平台上；未来（2022年以后）逐步将资料前处理和所有的产品制作都迁移到气象大数据云平台上。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/cmadaas/training/nwpc-cmadaas-plan-2020.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;NWPC 数值预报业务系统融入气象大数据云平台的规划&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;虽然业务系统融入气象大数据云平台是大势所趋，但对于上述方案，我仍持保留意见。
NWPC 的数值预报业务系统及数值模式研发工作，至少在我入职的 7 年以来，都只专注在 HPC 上。
短期内进行架构上的改变必然会遇到重重困难。&lt;/p&gt;
&lt;p&gt;无论从整个业务系统构建和维护角度，还是从我个人职业发展的角度来看，大数据云平台都会带来严峻的挑战。
在之前翻译的 ECMWF 两篇通讯文章中也有探讨。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-28-hpc2020-ecmwfs-new-high-performance-computing-facility/"&gt;视界：HPC 2020 - ECMWF 新高性能计算机&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-14-view-new-capabilities-ecmwfs-product-dissemination-system/"&gt;视界：ECMWF产品发布系统的新功能&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;通常情况下，挑战总会伴随着机遇，尤其在大变革的时代。
今天参加培训的主要目的之一，也是想看看是否能从各位专家的介绍中获得一丝关于机遇的灵感。
可惜，我还是没有把握住机会。&lt;/p&gt;
&lt;h2 id="感想"&gt;感想&lt;/h2&gt;
&lt;p&gt;我的个人账户没有气象大数据云平台任何资源的使用权限，所以只能从培训和文章资料中获取云平台的相关信息。&lt;/p&gt;
&lt;p&gt;在没有具体项目需求并实际使用的情况下，参加类似的培训似乎没有多大的帮助。
本次培训介绍的非常全面，但我依然感觉自己没有听到新的内容，与之前的介绍和小规模培训没有太大的差别。这可能是因为我确实能力有限，理解不到位，也可能是因为没有实际使用过，没有带着问题参加培训。&lt;/p&gt;
&lt;p&gt;有了解才有发言权，我了解得不够充分，想法就会比较片面，所以本文看看就好。&lt;/p&gt;
&lt;p&gt;当我们面临多种工作方向时，就需要进行选择。
向气象大数据云平台迁移虽然是数值预报业务系统重要的发展方向，但这仅仅是我工作任务的一部分，还有其他的任务方向可以选择。&lt;/p&gt;
&lt;p&gt;新建立的系统总要经过一段时间的发展，才能变得稳定和易用。
虽然早期参与者会获得先行优势，可能会在某种程度上影响系统的演变。
但我觉得我显然还达不到这么高的层次，不认为自己能在气象大数据云平台建设方面起到任何作用。
所以还不如等待先行者将各种未知的坑填平后，再进入到该领域。&lt;/p&gt;
&lt;p&gt;后入场的劣势在于，在系统已经定型的情况下，就只能按照给定的路线对现有业务系统进行改造，无法再提出自己的需求。
我并不在意这一点，因为我一直对气象大数据云平台的部分思路持保留意见。
直到现在，我依然觉得想要将整个气象局的所有算法都统一管理在一个平台下，是一个非常艰巨而庞大的目标。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我认为对算法的统一管理，才是气象大数据云平台最核心的建设思路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这意味着气象大数据云平台运行单位会深度介入到气象局所有的业务系统中，各项业务系统必须按照运行单位制定的各种规范构建。
打破烟囱和孤岛是一件好事情，但进展太快往往不会带来想要的结果。&lt;/p&gt;
&lt;p&gt;从个人角度来看，既然迁移工作可以通过工程项目来实现，还需要去详细了解气象大数据云平台的技术细节和融入规范么？
反正工程项目使用到的技术往往都不在我的技能范畴内。
而摆在面前可以选择的方向还有很多，比如研发数据工具，参与诊断工具开发，寻找统计指标的快速计算方法，尝试机器学习算法等等。
每一个方向都与 NWPC 的核心任务，即数值预报模式研发，有着密切的关系。
而融入气象大数据云平台仅能作为一个工程类的项目，与 NWPC 的核心任务没有直接关系。&lt;/p&gt;
&lt;h2 id="题外话"&gt;题外话&lt;/h2&gt;
&lt;p&gt;我更倾向于使用以开源软件为代表的通用技术，而不是仅在特定单位使用的特有技术。
在我看来，气象大数据云平台虽然提供诸如数据库、消息中间件等通用技术，但整体思路还属于专有技术。&lt;/p&gt;
&lt;p&gt;云平台去年就发布了 MUSIC 2.0 版本的数据接口。
我在去年 9 月份写了一篇文章，介绍如何将其中的 Python 接口改造为支持 Python 3。
详情参见 《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-25-cimiss-python-api/"&gt;改造CIMISS MUSIC接口的Python SDK&lt;/a&gt;》。&lt;/p&gt;</description></item><item><title>AMS机器学习课程：数据分析与预处理</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-26-ams-ml-python-course-data-analysis-and-preproc/</link><pubDate>Sun, 26 Jul 2020 22:59:02 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-26-ams-ml-python-course-data-analysis-and-preproc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AMS 机器学习 Python 教程，并有部分修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;本文来自 &lt;a href="https://github.com/djgagne/ams-ml-python-course"&gt;djgagne/ams-ml-python-course&lt;/a&gt; 项目，请在运行下面代码前执行该项目的 &lt;code&gt;download_data.py&lt;/code&gt; 文件下载需要的 csv 文件和 NetCDF 文件。&lt;/p&gt;
&lt;h2 id="机器学习途径"&gt;机器学习途径&lt;/h2&gt;
&lt;p&gt;大部分机器学习工作流包含 6 个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;探索性分析：加载和可视化数据以了解其分布方式以及不同变量之间的相互关系。&lt;/li&gt;
&lt;li&gt;预处理：将您的数据转换为更适合机器学习的形式。&lt;/li&gt;
&lt;li&gt;模型训练：使用您的预处理数据优化一个或多个机器学习模型。&lt;/li&gt;
&lt;li&gt;模型推断：将机器学习模型应用于训练集之外的数据。&lt;/li&gt;
&lt;li&gt;评估：确定您的机器学习模型的执行情况。&lt;/li&gt;
&lt;li&gt;解释：提取您的模型从数据中学到的知识。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在本节中，我们将介绍步骤 1 和 2。
您将学习教程数据集，对其进行探索，并执行一些预处理任务。&lt;/p&gt;
&lt;h2 id="短期课程数据和问题简介"&gt;短期课程数据和问题简介&lt;/h2&gt;
&lt;p&gt;该问题的目标是预测低级别涡流（low-level vorticity）超过特定阈值的概率，给定一个风暴的模拟雷达反射率 &amp;gt; 40 dBZ 和相关的地面风和温度场。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;netCDF 数据中的输入要素场&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;REFL_COM_curr (组合反射率)&lt;/li&gt;
&lt;li&gt;U10_curr (10 m 西东风分量，m/s)&lt;/li&gt;
&lt;li&gt;V10_curr (10 m 南北风分量，m/s)&lt;/li&gt;
&lt;li&gt;T2_curr (2m 温度，开尔文)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;预测要素&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RVORT1_MAX_future (每小时最大垂直涡流，高于地面 1 公里，每秒速度)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;其他值得关注的变量&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;time：风暴图像的有效时间&lt;/li&gt;
&lt;li&gt;i 和 j：来自原始 WRF 模式网格的行和列数组索引&lt;/li&gt;
&lt;li&gt;x 和 y：投影坐标（以 m 表示）&lt;/li&gt;
&lt;li&gt;masks：显示风暴轮廓的二进制网格。csv 文件中的聚合统计信息仅从蒙版中的正网格点中提取&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="使用-pandas-和-xarray-读取气象数据文件"&gt;使用 pandas 和 xarray 读取气象数据文件&lt;/h2&gt;
&lt;p&gt;首先我们需要导入本节中使用的库，并修改部分设置。&lt;/p&gt;</description></item><item><title>ecFlow笔记：使用SSD盘保存ecFlow生成文件</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-23-ecflow-notebook-use-ssd-for-ecflow-out-files/</link><pubDate>Thu, 23 Jul 2020 22:58:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-23-ecflow-notebook-use-ssd-for-ecflow-out-files/</guid><description>&lt;p&gt;NWPC 目前使用四个 ecFlow 服务，分布在 CMA-PI 业务分区的两个登陆节点上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;login_b01 上运行 nwpc_op（确定性业务系统），nwpc_qu（准业务系统）和 nwpc_pd（后处理系统）&lt;/li&gt;
&lt;li&gt;login_b02 上运行 nwpc_qu_eps（集合预报系统）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在业务高峰时段，即 00 时次运行的 13:00 - 14:00 之间，使用 ecflow ui 监视系统时经常出现无法获取服务运行状态的情况。&lt;/p&gt;
&lt;p&gt;在 ecflow ui 中显示效果如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/ssd/ui-disconnect-server.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ecFlow ui 无法获取 login_b09 的运行状态&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/ssd/ui-disconnect-server-info.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Info 面板中显示无法连接 ecFlow 服务的出错消息&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;虽然这个问题之前也一直存在，只要等待一会儿就可以再次看到系统的运行状态。
但 7 月 21 日整个一下午的时间都无法连接作业数较多的 nwpc_pd 和 nwpc_qu_eps 两个服务，严重影响运维工作，也导致产品出现延迟。&lt;/p&gt;
&lt;p&gt;我一直怀疑界面卡住的现象与磁盘IO性能有关，但缺乏足够的证据。&lt;/p&gt;
&lt;p&gt;之前写的两篇文章尝试分析定时任务为什么没有启动，很可能与界面卡住的原因类似。&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-12-ecflow-notebook-timed-task-not-run/"&gt;ecFlow笔记：定时任务没有启动 - 排查&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-13-ecflow-notebook-why-timed-task-not-run/"&gt;ecFlow笔记：定时任务没有启动 - 分析&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;本文介绍最近两天在信息中心的配合下，我们进行的一些尝试。&lt;/p&gt;
&lt;h2 id="分析"&gt;分析&lt;/h2&gt;
&lt;p&gt;下图以 GRAPES GFS 后处理系统为例说明 NWPC 数值预报业务系统 ecFlow 的目录结构。&lt;/p&gt;
&lt;p&gt;ecFlow 的 ecf 脚本和 include 文件保存在用户分区 &lt;code&gt;/g1/u&lt;/code&gt; 中。
可执行程序和绘图脚本也保存在该分区中。&lt;/p&gt;</description></item><item><title>将 Anaconda 移动到新的文件夹</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-22-move-anaconda-into-a-new-directory/</link><pubDate>Wed, 22 Jul 2020 20:53:11 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-22-move-anaconda-into-a-new-directory/</guid><description>&lt;p&gt;最近需要将 CMA-PI 上的个人目录从 /g3 迁移到 /g11。
我已在 /g3 的个人目录中安装 Anaconda3，并已在实时运行的测试系统中应用。&lt;/p&gt;
&lt;p&gt;虽然大部分软件都可以通过修改 PATH 环境变量或者修改 Modules 配置文件的方式支持目录迁移，但 Anaconda 环境却无法直接移动目录。&lt;/p&gt;
&lt;h2 id="原因"&gt;原因&lt;/h2&gt;
&lt;p&gt;conda 命令是一个 Python 脚本，从下面的源码中可以看到第一行指定了 Python 可执行程序的绝对路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/g3/wangdp/lang/python/anaconda3/bin/python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; sys
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Before any more imports, leave cwd out of sys.path for internal &amp;#39;conda shell.*&amp;#39; commands.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# see https://github.com/conda/conda/issues/6549&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; len(sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;argv) &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;and&lt;/span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;argv[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;startswith(&lt;span style="color:#e6db74"&gt;&amp;#39;shell.&amp;#39;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;and&lt;/span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path &lt;span style="color:#f92672"&gt;and&lt;/span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# The standard first entry in sys.path is an empty string,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# and os.path.abspath(&amp;#39;&amp;#39;) expands to os.getcwd().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;del&lt;/span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;from&lt;/span&gt; conda.cli &lt;span style="color:#f92672"&gt;import&lt;/span&gt; main
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sys&lt;span style="color:#f92672"&gt;.&lt;/span&gt;exit(main())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然直接修改第一行的路径可以让 conda 命令重新生效，但当运行 juypter 命令时依然会出错。&lt;/p&gt;</description></item><item><title>ecFlow笔记：获取任务节点数</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-21-ecflow-notebook-get-task-count/</link><pubDate>Tue, 21 Jul 2020 22:32:06 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-21-ecflow-notebook-get-task-count/</guid><description>&lt;p&gt;每天运行的任务数量是衡量系统规模的关键指标。&lt;/p&gt;
&lt;p&gt;ecFlow UI 界面中可以设置显示 Server 或 Suite 节点的子节点个数，如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/task-count/ecflow-ui-node-count-nwpc-qu-eps.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;nwpc_qu_eps 服务，包含全球和区域集合预报系统&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;但显示的节点个数包括 Family 等所有节点类型，而我们通常关心的仅仅是会实际提交任务的 Task 节点。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 ecFlow 的 Python API 获取 Task 节点个数。&lt;/p&gt;
&lt;h2 id="基本方法"&gt;基本方法&lt;/h2&gt;
&lt;p&gt;ecFlow API 中的 &lt;code&gt;ecflow.Defs&lt;/code&gt; 对象提供 &lt;code&gt;get_all_tasks()&lt;/code&gt; 函数，返回 ecFlow 服务中所有的任务节点个数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; ecflow
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ecflow&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Client(host, port)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sync_local()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;defs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_defs()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(len(defs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_all_tasks()))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;81674
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;返回的任务节点数（81674）比界面中的子节点数（83992）略少。&lt;/p&gt;
&lt;h2 id="进一步"&gt;进一步&lt;/h2&gt;
&lt;p&gt;上述方法返回的服务中所有 suite 的任务节点数。&lt;/p&gt;
&lt;p&gt;从上面的图中可以看到，ecFlow 服务中可能会有处于挂起状态（suspended）的系统。
这些系统不会提交任务，但也会被 &lt;code&gt;get_all_tasks()&lt;/code&gt; 函数计入到返回结果中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：笔者不建议在业务级别的 ecFlow 服务中保留挂起状态的历史系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果想要获取实际运行的任务节点个数，需要采用另外的方法。&lt;/p&gt;
&lt;p&gt;首先，获取 ecFlow 服务的所有节点运行状态，即 &lt;code&gt;ecflow.Defs&lt;/code&gt; 对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ecflow&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Client(args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;host, args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;port)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sync_local()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;defs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_defs()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后遍历 &lt;code&gt;defs&lt;/code&gt; 的所有 suite。&lt;/p&gt;</description></item><item><title>AI4ESS 2020：决策树和它们的森林</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-17-ae4ess-d1-s3-decision-trees-and-their-ensembles/</link><pubDate>Sat, 18 Jul 2020 13:33:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-17-ae4ess-d1-s3-decision-trees-and-their-ensembles/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AI4ESS 2020 课程，并有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Artificial Intelligence for Earth System Science (AI4ESS) Summer School&lt;/p&gt;
&lt;p&gt;Decision Trees and Their Ensembles&lt;/p&gt;
&lt;p&gt;Ryan Lagerquist - NOAA&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S3/D1-S3-P001.png"&gt;
&lt;/figure&gt;

&lt;h2 id="理论"&gt;理论&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S3/D1-S3-P002.png"&gt;
&lt;/figure&gt;

&lt;p&gt;决策树是具有分支节点（椭圆）和叶节点（矩形）的流程图。&lt;/p&gt;
&lt;p&gt;在上面的示例中，f 是极端天气的预测概率。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S3/D1-S3-P003.png"&gt;
&lt;/figure&gt;

&lt;p&gt;分支节点是分叉的，叶子节点是终止点。&lt;/p&gt;
&lt;p&gt;换句话说，每个分支节点有 2 个子节点，每个叶子节点有 0 个子节点。&lt;/p&gt;
&lt;p&gt;在叶子节点进行预测，并在分支节点提出问题。&lt;/p&gt;
&lt;p&gt;由于分支节点是分支的，因此在分支节点处提出的问题必须为是或否。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S3/D1-S3-P004.png"&gt;
&lt;/figure&gt;

&lt;p&gt;自 1960 年代以来（Chisholm 1968），决策树已用于气象学。&lt;/p&gt;
&lt;p&gt;它们由人类专家主观构建，直到 1980 年代，当时开发了一种目标算法（Quinlan 1986）来 “训练” 它们（确定每个分支节点的最佳问题）。&lt;/p&gt;
&lt;p&gt;叶节点 L 处的预测是达到 L 的所有训练样本的平均值。&lt;/p&gt;
&lt;p&gt;对于回归，这是一个真实值（达到 L 的平均冰雹大小）。&lt;/p&gt;
&lt;p&gt;对于分类，这是一个概率（严重冰雹达到 L 的暴风的分数）。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S3/D1-S3-P005.png"&gt;
&lt;/figure&gt;

&lt;p&gt;在每个分支节点处选择最大化信息增益的问题。&lt;/p&gt;
&lt;p&gt;对于回归，这是通过最小化均方误差来实现的（在预测值和实际值之间，例如冰雹大小）。&lt;/p&gt;
&lt;p&gt;对于分类，这是通过最小化 remainder 来完成的，remainder 是基于子节点的熵的。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S3/D1-S3-P006.png"&gt;
&lt;/figure&gt;

&lt;p&gt;一个节点的熵定义如下：&lt;/p&gt;
&lt;p&gt;\begin{equation*}
E=-\frac {1} {n}[\boldsymbol{f}log_{2}(\boldsymbol{f}) + (1-\boldsymbol{f})log_{2}(\boldsymbol{f})]
\end{equation*}&lt;/p&gt;</description></item><item><title>AI4ESS 2020：机器和统计学习基础：实际应用</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-16-ai4ess-d1-s2-machine-and-statistical-learning-fundamentals-section-3/</link><pubDate>Thu, 16 Jul 2020 23:04:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-16-ai4ess-d1-s2-machine-and-statistical-learning-fundamentals-section-3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AI4ESS 2020 课程，并有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Artificial Intelligence for Earth System Science (AI4ESS) Summer School&lt;/p&gt;
&lt;p&gt;Machine and Statistical Learning Fundamentals&lt;/p&gt;
&lt;p&gt;Dorit Hammerling - CSM / NCAR&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P000.png"&gt;
&lt;/figure&gt;

&lt;h2 id="实际应用"&gt;实际应用&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P050.png"&gt;
&lt;/figure&gt;

&lt;h3 id="研究动机"&gt;研究动机&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P051.png"&gt;
&lt;/figure&gt;

&lt;p&gt;大局：我们使用气候的自然变异性来模拟大气中一氧化碳（CO）浓度。&lt;/p&gt;
&lt;p&gt;动机：为什么要费心为一氧化碳建模？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;火灾是南半球二氧化碳的主要来源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一氧化碳可以用作火灾的代理变量。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;预测性 CO 模型可以帮助各国为大规模火灾事件做准备。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="响应变量"&gt;响应变量&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P052.png"&gt;
&lt;/figure&gt;

&lt;p&gt;Terra 卫星上来自 MOPITT 仪器的 CO 测量。&lt;/p&gt;
&lt;p&gt;CO 聚集到七个生物质火灾区。&lt;/p&gt;
&lt;p&gt;为每个区域创建独立的模型。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P053.png"&gt;
&lt;/figure&gt;

&lt;p&gt;响应变量：给定时间 t 的反季节化的 CO 异常。&lt;/p&gt;
&lt;h3 id="预测变量"&gt;预测变量&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P054.png"&gt;
&lt;/figure&gt;

&lt;p&gt;火灾事件通过燃料的可用性和干燥度与气候相关。&lt;/p&gt;
&lt;p&gt;气候指数是总结气候非周期性变化的指标。&lt;/p&gt;
&lt;p&gt;预测变量：气候指数，滞后t&lt;/p&gt;
&lt;h3 id="统计模型"&gt;统计模型&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P055.png"&gt;
&lt;/figure&gt;

&lt;p&gt;我们使用具有一阶相互作用项的滞后多元线性回归模型来解释大气 CO 与气候指数之间的关系。&lt;/p&gt;
&lt;p&gt;$$
CO(t)=\mu + \sum_{k}^{}a_{k}\cdot \chi_{k}(t-\tau_{k}) + \sum_{i,j}^{}b_{ij}\cdot\chi_{i}(t-\tau_{i})\cdot\chi_{j}(t-\tau_{j})
$$&lt;/p&gt;</description></item><item><title>AI4ESS 2020：机器和统计学习基础：函数形式，交叉验证和模型选择</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-14-ai4ess-d1-s2-machine-and-statistical-learning-fundamentals-section-2/</link><pubDate>Tue, 14 Jul 2020 21:43:42 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-14-ai4ess-d1-s2-machine-and-statistical-learning-fundamentals-section-2/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AI4ESS 2020 课程，并有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Artificial Intelligence for Earth System Science (AI4ESS) Summer School&lt;/p&gt;
&lt;p&gt;Machine and Statistical Learning Fundamentals&lt;/p&gt;
&lt;p&gt;Dorit Hammerling - CSM / NCAR&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P000.png"&gt;
&lt;/figure&gt;

&lt;h2 id="函数形式交叉验证和模型选择"&gt;函数形式，交叉验证和模型选择&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P028.png"&gt;
&lt;/figure&gt;

&lt;h3 id="如何估算-f"&gt;如何估算 f&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P030.png"&gt;
&lt;/figure&gt;

&lt;p&gt;回忆下模型的最简单形式：&lt;/p&gt;
&lt;p&gt;$$
Y = f(X) + \epsilon
$$&lt;/p&gt;
&lt;p&gt;估算 \(\hat{f}\) 的目标：&lt;/p&gt;
&lt;p&gt;寻找一个函数 \(\hat{f}\)，对于所有的 (X, Y) 都有 \(Y\approx\hat{f}(X)\)&lt;/p&gt;
&lt;p&gt;虽然具体细节依赖于特定的方法，但仍有一些通用的特性我们可以讨论。&lt;/p&gt;
&lt;p&gt;为了这样做，我们将方法分为参数化方法（例如使用函数形式）和非参数化方法。&lt;/p&gt;
&lt;h3 id="参数化方法"&gt;参数化方法&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P032.png"&gt;
&lt;/figure&gt;

&lt;p&gt;参数化建模包括两个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;假设函数形式&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;线性模型是一个简单的示例：&lt;/p&gt;
&lt;p&gt;\begin{equation*}
f(X)=\beta_{0}+\beta_{1}*X_{1}+\beta_{2}*X_{2}+&amp;hellip;+\beta_{p}&lt;em&gt;X_{p}
\end{equation&lt;/em&gt;}&lt;/p&gt;
&lt;p&gt;估算 f 问题现在简化为估算参数 \(\beta_{0},\beta_{1},\beta_{2},&amp;hellip;,\beta_{p}\)&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;使用 &lt;em&gt;训练数据&lt;/em&gt; 估计参数，用于拟合或训练模型&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;取决于函数的形式和参数的个数，这个步骤可能在数值上具有挑战性。
在简单的情况下，例如线性模型，有明确的解决方案，例如最小二乘法。&lt;/p&gt;
&lt;h3 id="非参数化方法"&gt;非参数化方法&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P035.png"&gt;
&lt;/figure&gt;

&lt;p&gt;非参数化模型没有对 f 的函数形式做出明确的假设。
相反，它们的目标是在符合平滑度约束的同时，估算接近数据的 f。&lt;/p&gt;</description></item><item><title>AI4ESS 2020：机器和统计学习基础：通用框架，推断与预测</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-13-ai4ess-d1-s2-machine-and-statistical-learning-fundamentals-section-1/</link><pubDate>Mon, 13 Jul 2020 23:02:08 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-13-ai4ess-d1-s2-machine-and-statistical-learning-fundamentals-section-1/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AI4ESS 2020 课程，并有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Artificial Intelligence for Earth System Science (AI4ESS) Summer School&lt;/p&gt;
&lt;p&gt;Machine and Statistical Learning Fundamentals&lt;/p&gt;
&lt;p&gt;Dorit Hammerling - CSM / NCAR&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P000.png"&gt;
&lt;/figure&gt;

&lt;h2 id="通用框架推理与预测"&gt;通用框架，推理与预测&lt;/h2&gt;
&lt;h3 id="有用的参考书"&gt;有用的参考书&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P003.png"&gt;
&lt;/figure&gt;

&lt;p&gt;免费，并且写得很好，都有良好的代码示例&lt;/p&gt;
&lt;p&gt;&lt;a href="http://faculty.marshall.usc.edu/gareth-james/ISL/"&gt;An Introduction to Statistical Learning with Applications in R&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;数学内容较少。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://web.stanford.edu/~hastie/ElemStatLearn/"&gt;The Elements of Statistical Learning&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;更偏向于数学。&lt;/p&gt;
&lt;h3 id="面向初学者的一些定义"&gt;面向初学者的一些定义&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P007.png"&gt;
&lt;/figure&gt;

&lt;p&gt;统计学习（Statistical learning）：大量可从数据中获取见解的工具&lt;/p&gt;
&lt;p&gt;监督 vs 非监督：输出 + 一个或更多的输入&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分类&lt;/li&gt;
&lt;li&gt;回归&lt;/li&gt;
&lt;li&gt;。。。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;监督学习：只有输入，对这些输入的结构更感兴趣&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;聚类&lt;/li&gt;
&lt;li&gt;相关分析&lt;/li&gt;
&lt;li&gt;降维，例如主成分分析&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本讲座将聚焦监督学习。&lt;/p&gt;
&lt;h3 id="基本模型方程"&gt;基本模型方程&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S2/D1-S2-P009.png"&gt;
&lt;/figure&gt;

&lt;p&gt;监督模型的最简单形式&lt;/p&gt;
&lt;p&gt;$$
Y = f(X) + \varepsilon
$$&lt;/p&gt;</description></item><item><title>AI4ESS 2020: 建立坚实的基础 - 定义机器学习问题和预处理</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-11-ai4ess-d1-s1-ml-problem-and-preprocessing/</link><pubDate>Sat, 11 Jul 2020 23:23:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-11-ai4ess-d1-s1-ml-problem-and-preprocessing/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 AI4ESS 2020 课程，并有部分修改&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Artificial Intelligence for Earth System Science (AI4ESS) Summer School&lt;/p&gt;
&lt;p&gt;Building a Strong Foundation: Defining ML Problems and Preprocessing&lt;/p&gt;
&lt;p&gt;David John Gagne - NCAR&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;h3 id="动机"&gt;动机&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S1/D1-S1-P004.png"&gt;
&lt;/figure&gt;

&lt;p&gt;过去三年来，人们对大气科学中的人工智能和机器学习的兴趣激增。&lt;/p&gt;
&lt;p&gt;大部分的注意力都集中在算法上，如深度学习，随机森林，或者其他更大的方法。&lt;/p&gt;
&lt;p&gt;但在实践中只是选择正确的机器学习算法不足以创建成功的人工智能/机器学习系统，不足以有效提供良好的决策以及所有我们正在寻找认为 AI 应该为我们完成的东西。&lt;/p&gt;
&lt;p&gt;每个机器学习项目的 80% 时间都花在以下两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定义机器学习问题，比如我们究竟是怎么做机器学习&lt;/li&gt;
&lt;li&gt;对数据进行预处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，我们如何从不适合进行机器学习的原始形式中获取数据。
一旦你完成这一步，训练部分会进行得相对较快， 但到达这一步可能是相当艰难的旅程&lt;/p&gt;
&lt;p&gt;本讲座将讨论训练任何机器学习模型之前必须做出的许多重要选择。&lt;/p&gt;
&lt;h3 id="数据科学术语"&gt;数据科学术语&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ai4ess-2020/D1/S1/D1-S1-P005.png"&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;数据科学&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;专注从数据中提取知识和见解的方法。&lt;/p&gt;
&lt;p&gt;包含人工智能方法。但也有一大堆其他数据科学工具和技术，不使用 AI 系统，用于处理非常大的数据，进行分析，并获取关于数据的见解。&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;人工智能&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;让计算机系统从事人类任务的方法。&lt;/p&gt;
&lt;p&gt;所以这是一个包罗万象的术语， 有很多不同的方式来定义一个 AI 系统。
通常不只是像机器学习模型的单个组件，而是包含所有计算机需要与之交互的一切，包括任何与外部交互的接口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;专家系统&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用人类指定的规则自主操作。&lt;/p&gt;
&lt;p&gt;例如在大气科学中，模糊逻辑（fuzzy logic）是一种专家系统方法，它已经获得了相当的成效，因为现在仍然在一定程度上继续使用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;机器学习&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从数据学习具有指定结构的数学模型执行任务。&lt;/p&gt;
&lt;p&gt;我们发现，专家被证明是或并不总是能描述他们如何做决定，有很多边缘情况出现。&lt;/p&gt;
&lt;p&gt;因此，构建 AI 系统的一个更有效的方法就是给它很多任务示例和结果，然后根据该数据将数学模型或机器学习模型拟合到某种指定的结构（如神经网络或决策树）中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;深度学习&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;具有多个专用层的神经网络，用于编码结构信息。&lt;/p&gt;</description></item><item><title>简要介绍轴向上的聚合函数</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-10-a-small-talk-about-aggregate-function-in-given-axis/</link><pubDate>Fri, 10 Jul 2020 23:31:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-10-a-small-talk-about-aggregate-function-in-given-axis/</guid><description>&lt;p&gt;Python 矩阵库中都会包含对数组的聚合函数（也叫作缩减函数），比如 &lt;code&gt;sum&lt;/code&gt;，&lt;code&gt;mean&lt;/code&gt;，&lt;code&gt;std&lt;/code&gt; 等。&lt;/p&gt;
&lt;p&gt;这些方法都可以直接调用，返回单一的标量值。
也可以指定某个坐标轴，沿给定轴向上进行聚合，形成一个下降一个维度的数组。&lt;/p&gt;
&lt;p&gt;本文以 &lt;code&gt;sum&lt;/code&gt; 方法为例，通过图示简要介绍二维和三维矩阵中沿轴向的聚合函数。&lt;/p&gt;
&lt;h2 id="二维矩阵"&gt;二维矩阵&lt;/h2&gt;
&lt;p&gt;使用 NumPy 构造一个 2 x 3 的二维矩阵。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reshape(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([[0, 1, 2],
 [3, 4, 5]])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;生成的数组如下图所示，有两个维度。
第一个维度（dim 0）表示一行，第二个维度表示一列（dim 1）。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/python/aggregate-function-in-axis/2d-array.png"&gt;
&lt;/figure&gt;

&lt;h3 id="求和"&gt;求和&lt;/h3&gt;
&lt;p&gt;调用不带参数的 &lt;code&gt;sum()&lt;/code&gt; 方法，返回一个标量，即数组中所有元素的和。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sum()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;15
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下图是求和的示意图，在两个维度上累加，得到最终的结果。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/python/aggregate-function-in-axis/2d-array-sum.png"&gt;
&lt;/figure&gt;

&lt;h3 id="维度-0-求和"&gt;维度 0 求和&lt;/h3&gt;
&lt;p&gt;沿维度 0 求和，即沿列求和&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sum(axis&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([3, 5, 7])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;沿维度 0 求和相当于合并维度 0，仅保留维度 1，即将多行合并为 1 行，仅保留 3 列数据。
求和过程如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/python/aggregate-function-in-axis/2d-array-sum-dim-0.png"&gt;
&lt;/figure&gt;

&lt;h3 id="维度-1-求和"&gt;维度 1 求和&lt;/h3&gt;
&lt;p&gt;沿维度 1 求和，即沿行求和&lt;/p&gt;</description></item><item><title>使用cdo将GrADS数据转换成Grib2数据</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-09-cdo-convert-grads-to-grib2/</link><pubDate>Thu, 09 Jul 2020 20:13:05 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-09-cdo-convert-grads-to-grib2/</guid><description>&lt;p&gt;虽然 GRAPES 模式可以直接输出 GRIB 2 格式数据，但 NWPC 的模式试验通常选择输出 GrADS 二进制格式。
当需要与其他模式数据进行比较时，就无法避免需要将 GrADS 格式转成 GRIB2 格式。&lt;/p&gt;
&lt;p&gt;虽然 NWPC 已开发一些转码工具（例如 &lt;code&gt;grads2grib.exe&lt;/code&gt;等），但大多数工具仅提供二进制可执行程序，没有源码的工具很难推广应用，至少我个人不希望将自己的工作构建在非开源软件之上。
所以，我也一直在寻找一款合适的转码工具。&lt;/p&gt;
&lt;p&gt;cdo 提供强大的数据处理功能，支持常见的数据格式，也支持将 GrADS 数据转换成 Grib2 格式。&lt;/p&gt;
&lt;p&gt;本文介绍使用 cdo 将 GrADS 数据转换成 Grib2 数据的简单方法。&lt;/p&gt;
&lt;h2 id="开始"&gt;开始&lt;/h2&gt;
&lt;p&gt;执行一行命令就可以实现转码。&lt;/p&gt;
&lt;p&gt;下面的语句将 GRAPES GFS 输出的地面场和等压面场二进制数据 postvar 转码为 Grib 2 文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cdo -v -f grb2 import_binary post.ctl_2020070900_000 a.grb2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;grib_ls&lt;/code&gt; 查看转码后的文件内容：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_ls a.grb2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下省略部分输出内容。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;a.grb2
edition centre date dataType gridType stepRange typeOfLevel level shortName packingType
2 ecmf 20200709 af regular_ll 0 isobaricInhPa 10 u grid_ieee
2 ecmf 20200709 af regular_ll 0 isobaricInhPa 9 u grid_ieee
...
2 ecmf 20200709 af regular_ll 0 isobaricInPa 20 u grid_ieee
2 ecmf 20200709 af regular_ll 0 isobaricInPa 10 u grid_ieee
2 ecmf 20200709 af regular_ll 0 isobaricInhPa 10 v grid_ieee
...
2 ecmf 20200709 af regular_ll 0 isobaricInPa 10 v grid_ieee
2 ecmf 20200709 af regular_ll 0 isobaricInhPa 10 t grid_ieee
...
2 ecmf 20200709 af regular_ll 0 surface 0 unknown grid_ieee
2 ecmf 20200709 af regular_ll 0 surface 0 unknown grid_ieee
2 ecmf 20200709 af regular_ll 0 surface 0 unknown grid_ieee
257 of 257 grib messages in a.grb2

257 of 257 total grib messages in 1 files
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以看到，常用的变量，如 &lt;code&gt;u&lt;/code&gt;，&lt;code&gt;v&lt;/code&gt;，&lt;code&gt;t&lt;/code&gt; 等已经自动识别，但某些变量无法自动识别。&lt;/p&gt;</description></item><item><title>JupyterHub in Docker：定制环境</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-07-jupyterhub-docker-spawner-custom-contianer/</link><pubDate>Tue, 07 Jul 2020 23:06:05 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-07-jupyterhub-docker-spawner-custom-contianer/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/07/2020-07-06-jupyterhub-docker-spawner-simple/"&gt;JupyterHub In Docker：简单示例&lt;/a&gt;》介绍了使用 Docker 创建最简单的 JupyterHub 环境，为用户提供官方的 Jupyter 镜像。&lt;/p&gt;
&lt;p&gt;本文进一步介绍如何为用户提供定制的 Jupyter 环境，并提供额外的功能。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;DockerSpawner 中可以配置使用的 Docker 镜像。&lt;/p&gt;
&lt;p&gt;本文为 &lt;a href="https://github.com/nwpc-oper/nwpc-graphics"&gt;nwpc-oper/nwpc-graphics&lt;/a&gt; 项目构建 Docker 镜像，并内置 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库。&lt;/p&gt;
&lt;p&gt;为了保存用户文件，将 notebook 目录使用 Docker volume 挂载，保证用户的数据不会丢失。&lt;/p&gt;
&lt;p&gt;为了访问二级存储上的数据，需要将 /sstorage1 目录也同时挂载到 docker 容器中。&lt;/p&gt;
&lt;p&gt;另外，绘图脚本因为版权问题，也无法直接放到 docker 容器中，所以也要挂载到容器中。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/mage/blog/2020/juypter/hub/docker/custom/jupyterhub-docker-custom.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;示意图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="hub-镜像"&gt;Hub 镜像&lt;/h2&gt;
&lt;p&gt;修改前一篇文章中 Hub 镜像的 &lt;code&gt;jupyerhub_config.py&lt;/code&gt; 文件。&lt;/p&gt;
&lt;h3 id="权限"&gt;权限&lt;/h3&gt;
&lt;p&gt;使用 FirstUseAuthenticator 验证登录，用户在第一次登录时需要设置密码。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;JupyterHub&lt;span style="color:#f92672"&gt;.&lt;/span&gt;authenticator_class &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;firstuseauthenticator.FirstUseAuthenticator&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="notebook-镜像"&gt;notebook 镜像&lt;/h3&gt;
&lt;p&gt;使用下一节创建的 &lt;code&gt;graphics-notebook&lt;/code&gt; 镜像。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DockerSpawner&lt;span style="color:#f92672"&gt;.&lt;/span&gt;image &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;graphics-notebook&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="notebook-目录"&gt;notebook 目录&lt;/h3&gt;
&lt;p&gt;设置暴露给用户的 notebook 目录。
本文的 notebook 镜像基于jupyter/docker-stacks 系列镜像构建，使用的用户名均为 &lt;code&gt;jovyan&lt;/code&gt;。
所以 notebook 目录可以设置为 &lt;code&gt;'/home/jovyan/work'&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>JupyterHub In Docker：简单示例</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-06-jupyterhub-docker-spawner-simple/</link><pubDate>Mon, 06 Jul 2020 22:18:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-06-jupyterhub-docker-spawner-simple/</guid><description>&lt;p&gt;本文介绍如何使用 Docker 搭建最简单的 JupyterHub 服务。&lt;/p&gt;
&lt;p&gt;示例来自 &lt;a href="https://github.com/jupyterhub/dockerspawner"&gt;jupyter/dockerspawner&lt;/a&gt; 的源码。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;本文依照官方示例，在单个主机上搭建最简单的 JupyterHub 服务。&lt;/p&gt;
&lt;p&gt;JupyterHub 服务运行在名为 Hub 的容器中，并为每个用户创建自己的 docker 容器。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/juypter/hub/docker/simple/jupyterhub-docker-simple.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;示意图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;下载 jupyterhub 镜像，该镜像包含 jupyerhub 的基本组件，但不包含 notebook&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker pull jupyter/jupyterhub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下载为用户实际运行的 jupyter 镜像&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker pull jupyter/base-notebook
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="创建网络"&gt;创建网络&lt;/h2&gt;
&lt;p&gt;为 jupyterhub 创建一个单独的 Docker 网络 &lt;code&gt;jupyterhub&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker network create jupyterhub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="构建镜像"&gt;构建镜像&lt;/h2&gt;
&lt;p&gt;jupyterhub 镜像使用默认的配置，想要使用 Docker 运行 jupyterhub，并且想为每个用户运行单独的 Docker 容器，需要构建自己的镜像。&lt;/p&gt;
&lt;p&gt;镜像需要安装额外的 python 包：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dockerspawner：使用 Docker 为用户创建 notebook&lt;/li&gt;
&lt;li&gt;jupyterhub-dummyauthenticator：模拟验证过程，可以输入任意用户，仅用于测试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将上述包放到 &lt;code&gt;requirements.txt&lt;/code&gt; 文件中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dockerspawner
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jupyterhub-dummyauthenticator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外，需要为 jupyterhub 定义配置文件 &lt;code&gt;jupyter_config.py&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>Docker中使用HTTP代理</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-03-using-proxy-in-docker/</link><pubDate>Fri, 03 Jul 2020 22:03:07 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-03-using-proxy-in-docker/</guid><description>&lt;p&gt;内网中的虚拟机都没有外网访问权限，无法直接进行在线安装。&lt;/p&gt;
&lt;p&gt;虽然 CMA 有自己的镜像网站：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://mirrors.cma.cn/"&gt;http://mirrors.cma.cn/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;但缺乏操作系统之外的镜像，比如 pip，anaconda 和 DockerHub 等。
所以配置 Python 环境和编排 Docker 镜像都不是很方便。&lt;/p&gt;
&lt;p&gt;我在之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-04-22-user-level-python-for-hpc/"&gt;HPC用户安装Python解决方案&lt;/a&gt;》中介绍使用在工作电脑上搭建的代理服务可以在线安装 Python 包。
本文介绍如何在 Docker 中使用代理。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;Docker 有三个地方需要网络访问：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下载 Docker 镜像：Docker 服务&lt;/li&gt;
&lt;li&gt;编排 Docker 镜像：Docker 客户端&lt;/li&gt;
&lt;li&gt;运行 Docker 容器：Docker 容器运行时&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面分别介绍设置代理的方法。&lt;/p&gt;
&lt;h2 id="docker-服务"&gt;Docker 服务&lt;/h2&gt;
&lt;p&gt;下载 Docker 镜像由 Docker 服务完成。&lt;/p&gt;
&lt;p&gt;Docker 服务使用启动时的 &lt;code&gt;HTTP_PROXY&lt;/code&gt;，&lt;code&gt;HTTPS_PROXY&lt;/code&gt; 和 &lt;code&gt;NO_PROXY&lt;/code&gt; 环境变量配置 HTTP 代理。&lt;/p&gt;
&lt;p&gt;使用 systemd 管理的 Docker 服务需要单独设置配置文件。&lt;/p&gt;
&lt;p&gt;为 Docker 服务创建 systemd drop-in 目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo mkdir -p /etc/systemd/system/docker.service.d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建名为 &lt;code&gt;/etc/systemd/system/docker.service.d/http-proxy.conf&lt;/code&gt; 的文件，添加环境变量&lt;/p&gt;</description></item><item><title>2020年第二季度工作总结</title><link>https://blog.perillaroc.wang/post/2020/07/2020-07-01-2020-q2-summary/</link><pubDate>Wed, 01 Jul 2020 14:15:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/07/2020-07-01-2020-q2-summary/</guid><description>&lt;p&gt;想要一直保持积极的工作状态是一件很困难事情。
回看第二季度，就能明显发现我的工作效果远远比不上第一季度。
也许第二季度才是更普遍的情况，毕竟诸如业务系统建设等偏向于工程类的工作会占用大量时间，但很难作为核心工作业绩。&lt;/p&gt;
&lt;h2 id="业务系统"&gt;业务系统&lt;/h2&gt;
&lt;p&gt;第一季度总结中我计划用最快的时间完成系统升级建设任务，实际上这项工作从 5 月一直持续到 6 月底。&lt;/p&gt;
&lt;h3 id="grapes-meso-v50-后处理"&gt;GRAPES MESO v5.0 后处理&lt;/h3&gt;
&lt;p&gt;GRAPES MESO 系统从 v4.3 升级到 v5.0，由 GRAPES MESO 3km 代替原有 GRAPES MESO 10km 系统。
原有 MESO 3km 后处理系统支持 v5.0 的每天 8 次快速循环同化。
同时将 MESO 10km 后处理系统中的图片产品移植到 MESO 3km，并将 NMC 网站产品任务单独组织到一个新系统中。&lt;/p&gt;
&lt;p&gt;详情请参看以下文章：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-31-nwpc-notebook-build-image-production-script/"&gt;NWPC笔记：构建图片产品制作脚本&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-13-nwpc-notebook-grapes-meso-3km-post-system-report/"&gt;NWPC笔记：GRAPES_MESO v5.0 后处理系统运行报告&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-25-nwpc-notebook-upgrade-grapes-meso-3km-post-for-cold-start/"&gt;NWPC笔记：为GRAPES_MESO v5.0后处理增加冷启动数据支持&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;因为 3km 系统预报时效只有 36 小时，原有 10km 00 和 12 时次长时效产品将由 GRAPES TYM 系统（即 GRAPES MESO 9km）替代。
修改 GRAPES TYM 系统配置，增加运行时次，缩小模式输出间隔，并增加 modelvar 输出。
同时使用 GRAPES TYM 的输出绘制 MESO 10km 长时效的图片产品。&lt;/p&gt;</description></item><item><title>NWPC笔记：GRAPES GFS v3.0后处理系统升级进行中</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-28-nwpc-notebook-upgrading-grapes-gfs-post/</link><pubDate>Sun, 28 Jun 2020 22:57:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-28-nwpc-notebook-upgrading-grapes-gfs-post/</guid><description>&lt;p&gt;没想到 GRAPES GFS v3.0 的升级会与 GRAPES MESO v5.0 业务切换交织在一起，导致最近几天疲于应付后处理系统建设任务，耽误了部分写作时间。&lt;/p&gt;
&lt;p&gt;GRAPES MESO v5.0 后处理系统已在去年进行完全重构，并在今年 5 月份完成平行试验系统的搭建。
最近将 00 和 12 时次的产品切换由冷启动数据驱动，在 &lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-oper/nwpc-data-client&lt;/a&gt; 项目的支持下，仅需要增加配置文件，并少量修改脚本就可以实现。
当然，如果想要保持足够的灵活性，还需要增加新的机制，已在《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-25-nwpc-notebook-upgrade-grapes-meso-3km-post-for-cold-start/"&gt;NWPC笔记：为GRAPES_MESO v5.0后处理增加冷启动数据支持&lt;/a&gt;》中介绍。&lt;/p&gt;
&lt;p&gt;而今天刚进行测试，并将于后天进行业务化评审的 GRAPES GFS v3.0，就不是一样的剧本。
GRAPES GFS 后处理系统属于历史遗留代码。
自接手以来的两年中，我仅重构了数据产品任务的脚本，对整体结构和大量的绘图任务脚本都没做彻底的改动。
源自 GRAPES MESO 后处理系统的建设经验也没有应用到该系统中。
如果我保留目前的系统结构，那么只需要修改接入数据的地址，使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-oper/nwpc-data-client&lt;/a&gt; 项目获取模式输出地址即可。
但我想对整个后处理系统进行全面重构，使用与 GRAPES MESO v5.0 后处理系统一样的结构。
这正是最近几天忙碌的原因。&lt;/p&gt;
&lt;p&gt;借鉴已有系统的经验，重构 GRAPES GFS 后处理系统更像是一种重复劳动，按照同样的标准逐个修改任务脚本即可。
不过，有两个问题仍然值得我深思：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;到底应不应该重构历史遗留代码&lt;/li&gt;
&lt;li&gt;系统建设能带来什么&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="对待历史遗留代码"&gt;对待历史遗留代码&lt;/h2&gt;
&lt;p&gt;到底需不需要重构历史遗留代码？&lt;/p&gt;
&lt;p&gt;这是一个很值得思考的问题。为了保持代码的生命力，需要持续更新代码。
不过，任何工作都需要投入时间，在时间有限的情况下，就需要有所权衡。&lt;/p&gt;
&lt;p&gt;从代码重构中可能获得些许编程经验，但我确实不知道获得的经验是否值得时间上的投入。
曾看到有文章不建议按照编码规范重构现有代码，认为与其浪费时间优化代码结构，不如多学点儿其它的东西。
当我接手 GRAPES GFS 后处理系统时，我也是这样想的。
升级切换只需要修改接入的数据，其余部分几乎不用改变。&lt;/p&gt;
&lt;p&gt;不过，当去年我想要增加新的模块时，发现实在无法在原有系统结构中修改，就重构了数据处理部分。
今年升级并没有增加新模块，似乎不需要进行大范围的修改。
经过一番思考，我还是决定参照最新的后处理系统结构重写 GRAPES GFS 后处理系统。&lt;/p&gt;
&lt;p&gt;我认为，如果预计代码会由自己长时间维护，为了提高后续工作的效率，很有必要对历史代码进行重构，持续提高整个系统的灵活性，以便能快速响应后续多变的需求。
在系统足够灵活的情况下，后处理系统的升级切换就可能成为一件很容易的工作。&lt;/p&gt;
&lt;p&gt;我也不确定持续修改系统代码是不是浪费时间。
但既然已经开始执行，就应该思考下如何做才能让时间花得更有意义。
这就引出第二个问题。&lt;/p&gt;</description></item><item><title>NWPC笔记：为GRAPES_MESO v5.0后处理增加冷启动数据支持</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-25-nwpc-notebook-upgrade-grapes-meso-3km-post-for-cold-start/</link><pubDate>Thu, 25 Jun 2020 21:49:04 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-25-nwpc-notebook-upgrade-grapes-meso-3km-post-for-cold-start/</guid><description>&lt;p&gt;两周前我将文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-13-nwpc-notebook-grapes-meso-3km-post-system-report/"&gt;NWPC笔记：GRAPES_MESO v5.0 后处理系统运行报告&lt;/a&gt;》作为 GRAPES_MESO v5.0 后处理系统升级工作完结的纪念。&lt;/p&gt;
&lt;p&gt;可惜我还是太乐观了：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;系统更新工作永远没有尽头。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;作为数值预报业务系统的建设人员，尤其是变更频繁的后处理系统的建设人员，我一直尽可能保持系统的灵活性，提高系统变更的效率。&lt;/p&gt;
&lt;p&gt;本文介绍最近几天更新的 GRAPES_MESO v5.0 后处理系统，支持包括冷启的多种数据组合。&lt;/p&gt;
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;GRAPES_MESO v5.0 系统包含两个冷启动时次（00和12）和八个暖启动时次（00,03,06,09,12,15,18,21），每个时次都有 36 小时预报。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/cold-start/grapes-meso-v5-system.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES_MESO v5.0 主模式系统&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;在业务化评审时，后处理产品均来自八个暖启动时次。
但因为某些原因，单位计划用冷启动时次的数据制作 00 和 12 两个时次的产品。&lt;/p&gt;
&lt;p&gt;虽然针对特定的时次在脚本中直接修改比较容易，但为了应对后续可能的需求，还是应该从灵活性上入手，让后处理系统可以适应多样的需求。&lt;/p&gt;
&lt;p&gt;比如，后续可能会再次使用暖启动数据制作 00 和 12 两个时次的产品；
或者全部 10 个时次的产品都需要生成。&lt;/p&gt;
&lt;p&gt;为了实现冷暖启动的灵活组合，需要在现有系统基础上增加新的机制，仅通过需要修改配置信息就可以实现数据的切换。&lt;/p&gt;
&lt;h2 id="现状"&gt;现状&lt;/h2&gt;
&lt;p&gt;目前系统使用如下的字段对象配置时次信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;00&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;07:00&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;36h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;03&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;09:00&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;36h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;字典中的每个顶层 key 代表一个时次，会在系统中添加以该 key 名称命名的时次 family。&lt;/p&gt;
&lt;p&gt;该 family 会添加 &lt;code&gt;HH&lt;/code&gt; 变量，值为 key 名称，代表时次，会被用于构造产品目录、名称等一系列任务。&lt;/p&gt;
&lt;p&gt;任务脚本中会使用 &lt;code&gt;HH&lt;/code&gt; 构造形如 &lt;code&gt;YYYYMMDDHH&lt;/code&gt; 的变量，用于创建运行目录。&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志解析 - 服务端记录</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-24-ecflow-notebook-parse-server-command-log/</link><pubDate>Wed, 24 Jun 2020 21:19:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-24-ecflow-notebook-parse-server-command-log/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/"&gt;ecFlow笔记：ecFlow日志解析 - 通用字段&lt;/a&gt;》介绍如何解析 ecFlow 日志的通用字段。&lt;/p&gt;
&lt;p&gt;本文介绍如何解析服务端记录（&lt;code&gt;ServerLogRecord&lt;/code&gt;）类型的 ecFlow 日志条目。&lt;/p&gt;
&lt;p&gt;本文代码均来自 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;目前 NWPC 使用的 ecflow 服务日志中，服务端记录仅有一种类型：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[20:29:54 28.5.2020] svr:check_pt in 0 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;表示服务端执行 checkpoint 操作。&lt;/p&gt;
&lt;p&gt;目前 NWPC 工作流日志工具尚未使用服务端记录，所以仅做简单的解析。&lt;/p&gt;
&lt;h2 id="结构"&gt;结构&lt;/h2&gt;
&lt;p&gt;服务端记录（&lt;code&gt;ServerLogRecord&lt;/code&gt;）的结构继承自通用日志结构（&lt;code&gt;EcflowLogRecord&lt;/code&gt;），将 Event 字段设置为状态变化 &lt;code&gt;EventType.Server&lt;/code&gt;。
同时增加命令（Command）字段，记录执行的命令。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/workflow-log/ecflow-log-parser/server/server-record.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;服务端记录结构&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="解析"&gt;解析&lt;/h2&gt;
&lt;p&gt;在经过通用解析后，从 command 字段中提取服务端命令设置为命令字段（Command）。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/workflow-log/ecflow-log-parser/server/server-record-parse.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;服务端记录解析&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;请参考 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-workflow-log-model&lt;/a&gt; 项目的 &lt;code&gt;ServerLogRecord&lt;/code&gt; 类的 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model/blob/6c2ddee2dd9395af68f5a71f7976a022e3ea0f10/nwpc_workflow_log_model/log_record/ecflow/server_record.py#L26"&gt;parse_record 函数&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以下代码来自该函数，其中 &lt;code&gt;self&lt;/code&gt; 表示 &lt;code&gt;EcflowLogParser&lt;/code&gt; 类，&lt;code&gt;line&lt;/code&gt; 是解析过通用字段后剩余的日志条目字符串。即&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;check_pt in 0 seconds
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;查找 &lt;code&gt;&amp;quot; &amp;quot;&lt;/code&gt;，获取命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;start_pos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end_pos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find(&lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#34;&lt;/span&gt;, start_pos)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line[start_pos:end_pos]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;event &lt;span style="color:#f92672"&gt;=&lt;/span&gt; event
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;event
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;项目：&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志解析 - client 命令记录</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-23-ecflow-notebook-parse-client-command/</link><pubDate>Tue, 23 Jun 2020 22:17:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-23-ecflow-notebook-parse-client-command/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/"&gt;ecFlow笔记：ecFlow日志解析 - 通用字段&lt;/a&gt;》介绍如何解析 ecFlow 日志的通用字段。&lt;/p&gt;
&lt;p&gt;本文介绍如何解析 client 命令记录（&lt;code&gt;ClientLogRecord&lt;/code&gt;）类型的 ecFlow 日志条目。&lt;/p&gt;
&lt;p&gt;本文代码均来自 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;client 命令记录主要包括记录不属于 child 子命令的 ecflow_client 命令调用，以及 UI 客户端与 ecflow 服务的通讯。&lt;/p&gt;
&lt;p&gt;大部分 client 命令都与人工操作有关。例如对于某些无法完成的任务，需要值班员手动设为 complete 状态；大量任务出错补做时，可以使用 requeue aborted 命令。&lt;/p&gt;
&lt;p&gt;目前 NWPC 工作流日志工具尚未关注 client 命令，所以仅做简单介绍。&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;下面举例说明常用命令的日志。&lt;/p&gt;
&lt;h3 id="节点命令"&gt;节点命令&lt;/h3&gt;
&lt;h4 id="requeue"&gt;requeue&lt;/h4&gt;
&lt;p&gt;requeue 命令用于将所有任务重新排队，是最常用的维护操作之一。&lt;/p&gt;
&lt;p&gt;默认情况下，&lt;code&gt;requeue&lt;/code&gt; 会重新排队所有的子节点。
例如下面日志来自数据转码任务，转码任务出错后，重新排队 &lt;code&gt;/grapes_tym_post/00/data/001&lt;/code&gt; 节点，该节点所有子任务会进入 &lt;code&gt;queued&lt;/code&gt; 状态。
随后，根据依赖关系，&lt;code&gt;pre_data2grib2&lt;/code&gt; 会立即被提交。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[06:58:28 26.5.2020] --requeue force /grapes_tym_post/00/data/001 :nwp_pd
LOG:[06:58:28 26.5.2020] queued: /grapes_tym_post/00/data/001
LOG:[06:58:28 26.5.2020] queued: /grapes_tym_post/00/data/001/pre_data2grib2
LOG:[06:58:28 26.5.2020] queued: /grapes_tym_post/00/data/001/data2grib2
LOG:[06:58:28 26.5.2020] queued: /grapes_tym_post/00/data/001/orig_grib2
LOG:[06:58:28 26.5.2020] queued: /grapes_tym_post/00/data/001/fy4a_bin
LOG:[06:58:28 26.5.2020] queued: /grapes_tym_post/00/data/001/cmacast
LOG:[06:58:28 26.5.2020] submitted: /grapes_tym_post/00/data/001/pre_data2grib2 job_size:5232
LOG:[06:58:28 26.5.2020] submitted: /grapes_tym_post/00/data/001
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;requeue 也支持仅排队出错的任务。
下面的日志将 &lt;code&gt;/swfdp&lt;/code&gt; 下所有出错的绘图任务重新排队，符合依赖关系的任务会立即重新运行。&lt;/p&gt;</description></item><item><title>从招聘信息中寻找自身差距</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-20-find-your-own-gap-from-recruitment-information/</link><pubDate>Sun, 21 Jun 2020 13:53:01 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-20-find-your-own-gap-from-recruitment-information/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;今天看到同事在朋友圈中转发某气象行业公司的招聘信息。
我在几年前稍微关注过这家公司招聘的岗位，所以就看了下这篇公众号文章。
发现其中一个岗位的职责几乎等同于我现在所负责的工作，令我感到很意外。&lt;/p&gt;
&lt;p&gt;在我的认知中，数值天气预报模式业务系统运维是极其小众的岗位。
除非和我们单位一样需要实时运行大量的业务系统，否则不会设立单独的岗位负责在应用层面上的维护。
记得最后一次持续关注招聘信息是在两年前，当时还没有找到完全对应上的职位。
所以我看的岗位大体上都和 C++/Qt 或者 Python 相关。
没想到现在都能看到涵盖在本部门职责中的招聘岗位，可能最近一段时间气象领域公司的业务扩展比较快，都需要专职人员来负责数值模式系统的开发和维护。&lt;/p&gt;
&lt;p&gt;虽然我认为部门在数值预报业务系统运维领域处于国内领先水平（谜一样的自信，刚被与 NCEP NCO 做对比并惨败），但招聘信息往往能给出业界对该岗位的期待，非常适合用来对比并寻找自身的差距。&lt;/p&gt;
&lt;p&gt;下面就简要对比下岗位职责和任职资格，引用部分来自招聘信息。&lt;/p&gt;
&lt;h2 id="岗位职责"&gt;岗位职责&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1.熟悉公司后台模式预报任务及各环节流程；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;基本要求，只有熟悉业务才能进行业务开发。
不过，单位的业务由部门的多人开发，并与多个部门关联，环节较多。
可能我只对自己负责建设的业务系统比较熟悉，而对其他同事负责的系统不够了解。&lt;/p&gt;
&lt;p&gt;最近的部门讨论已确定后续加强对业务系统的内部培训，让大家对各个系统都有所了解。
我觉得这是一个很好的开始，加强分享有助于增进了解，新想法往往就诞生于思想碰撞中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2.协助项目经理完成项目实施的各个环节，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;搭建新项目的大气模式业务化预报任务&lt;/li&gt;
&lt;li&gt;解决项目预报任务过程中所遇的技术问题&lt;/li&gt;
&lt;li&gt;维护Linux后台大气模式运行脚本&lt;/li&gt;
&lt;li&gt;模式业务运行系统的搭建和维护&lt;/li&gt;
&lt;li&gt;气象数据的管理&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;我对该公司不够了解，从“项目经理”和“项目实施”看，很可能是以工程项目的形式为第三方搭建业务系统。
职责整理下可以分成两个部分：模式业务系统搭建和维护；数据管理。均在部门的职责范围内。&lt;/p&gt;
&lt;p&gt;不过，第二项 “解决。。。技术问题” 如果涉及到数值模式系统本身的技术问题，就远远超出我目前的工作范围。
在业务系统建设方面，我目前承担类似胶水的角色，负责搭建业务流程，将其他同事开发的程序整合到一起，而不负责开发实际的程序。
当然，这也意味着我所从事的工作不属于单位的核心任务，很难在单位的拼图中成为不可或缺的一块，更缺乏获得广泛共识的成果。
就连信息中心的高性能计算室都在持续研究并行计算技术，所以我更应该仔细思考下在现有框架下自己的定位，拿出有影响力的工作业绩。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;3.负责在项目营运过程中监控预报任务，发现因数据下载延迟及其它突发性故障时能及时处理；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;业务运行监控是我们部门最重要的工作职责。
数据下载延迟是业务系统故障的重要来源之一，另外还有诸如数据分发异常、高性能计算机异常等等。
部门在这方面积累了足够丰富的经验，能够在复杂的环境中保障业务系统稳定运行。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;4.从模式输出数据中读取整理客户需求数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果仅仅需要对数据进行诸如要素抽取、区域裁剪等简单操作，那么用现有的开源命令行工具（如 &lt;code&gt;wgrib2&lt;/code&gt;）就可以很容易实现。
但是想要根据用户的需求在模式输出要素的基础上生成新的产品，就涉及到模式后处理。&lt;/p&gt;
&lt;p&gt;模式后处理是一项专业性很强的任务，在单位中由单独的部门负责，另外也有专门的团队从事数值预报模式数据释用方面的研究。
对于像我这样的业务系统运维人员来说，从数据处理方面切入到模式系统核心体系是最可能有效的途径。
毕竟数据处理涉及的专业领域知识远远小于模式系统本身。
实际上，最近关于某产品时效性的讨论中，领导提到我们部门应该着手开发并行转码程序。
虽然因为种种原因目前尚未开展，但至少说明在数据处理方面，我们部门有进一步发展的机会。&lt;/p&gt;
&lt;p&gt;另外，数据处理，乃至延伸的模式后处理是提供产品服务的关键技术。
在气象局范围内，就有多个单位的多个团队在对模式输出产品进行再加工。
即将组建的气象大数据中心更能体现数据在气象领域的重要性。
之前我过于担心在数据方面投入太多会导致未知的冲突。
不过在无法明确未来改革方向的情况下，进行数据处理方面的研究总会有所帮助。
不能将自己限制在某个固定的范围内，但也要处理好涉猎太广而带来的不专精的问题。&lt;/p&gt;
&lt;p&gt;大数据时代，数据才是最有价值的资源，掌握围绕数据的各项技术才能具备核心竞争力。&lt;/p&gt;
&lt;h2 id="任职资格"&gt;任职资格&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1、大气科学、物理学、计算机或自动化相关专业，硕士及以上学历；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这一点与职位要求有所冲突。职位要求有 5-10 年工作经验，博士及以上学历。
这是很高的标准，至少在我们单位从事数值预报业务系统维护的同事中，没有人符合这项要求。&lt;/p&gt;
&lt;p&gt;可能需要去读个在职博士🤣&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2、掌握中尺度大气数值模拟的相关知识，长期从事数值天气预报系统维护与优化工作；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们部门除了去年刚入职的新同事，至少都有 5 年以上的数值预报业务系统运维经验。&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志解析 - child 命令记录</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-18-ecflow-notebook-parse-child-command-log/</link><pubDate>Fri, 19 Jun 2020 20:22:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-18-ecflow-notebook-parse-child-command-log/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/"&gt;ecFlow笔记：ecFlow日志解析 - 通用字段&lt;/a&gt;》介绍如何解析 ecFlow 日志的通用字段。&lt;/p&gt;
&lt;p&gt;本文介绍如何解析 child 命令记录（&lt;code&gt;ChildLogRecord&lt;/code&gt;）类型的 ecFlow 日志条目。&lt;/p&gt;
&lt;p&gt;本文代码均来自 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;ecFlow 服务并不负责监控任务的运行状态，而是要求任务自身将运行状态告知给 ecFlow 服务，这就需要使用到 child 命令。&lt;/p&gt;
&lt;p&gt;child 命令是 &lt;code&gt;ecflow_client&lt;/code&gt; 的一组子命令，主要用于实现任务脚本与 ecFlow 服务之间的通讯，修改 ecFlow 服务中与某个任务节点相关的属性。&lt;/p&gt;
&lt;p&gt;目前，NWPC 的数值预报业务系统中使用的 child 命令主要包括以下两种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改任务节点状态：&lt;code&gt;init&lt;/code&gt;，&lt;code&gt;complete&lt;/code&gt; 和 &lt;code&gt;abort&lt;/code&gt;，命令调用不需要额外的参数，全部由环境变量指定&lt;/li&gt;
&lt;li&gt;修改任务节点的属性子节点：&lt;code&gt;event&lt;/code&gt;，&lt;code&gt;meter&lt;/code&gt; 和 &lt;code&gt;label&lt;/code&gt;，任务节点可能有多个同一类的属性子节点，所以命令调用时需要指定属性的名称&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;child 命令示意图如下所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/workflow-log/ecflow-log-parser/child/child-command-v2.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;child 命令记录&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;下面举例说明各个命令的日志。&lt;/p&gt;
&lt;h3 id="init"&gt;init&lt;/h3&gt;
&lt;p&gt;init 命令用于告知 ecFlow 服务任务已实际开始运行。
执行 &lt;code&gt;init&lt;/code&gt; 命令后，节点状态会变为 &lt;code&gt;active&lt;/code&gt;。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[13:25:26 14.5.2020] chd:init /grapes_emer_v1_2/00_2/upload/upload_plot_ty
LOG:[13:25:26 14.5.2020] active: /grapes_emer_v1_2/00_2/upload/upload_plot_ty
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="complete"&gt;complete&lt;/h3&gt;
&lt;p&gt;complete 命令用于告知 ecFlow 服务任务已经正常结束。
执行 &lt;code&gt;complete&lt;/code&gt; 命令后，节点状态会变为 &lt;code&gt;complete&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志解析 - 状态变化记录</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-17-ecflow-notebook-parse-status-log/</link><pubDate>Wed, 17 Jun 2020 22:04:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-17-ecflow-notebook-parse-status-log/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/"&gt;ecFlow笔记：ecFlow日志解析 - 通用字段&lt;/a&gt;》介绍如何解析 ecFlow 日志的通用字段。&lt;/p&gt;
&lt;p&gt;本文介绍如何解析状态变化记录（&lt;code&gt;StatusLogRecord&lt;/code&gt;）类型的 ecFlow 日志条目。&lt;/p&gt;
&lt;p&gt;本文代码均来自 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;ecFlow 实现工作流的核心机制就是跟踪任务（Task）节点的状态，并定时根据状态决定工作流应采取的下一步动作。&lt;/p&gt;
&lt;p&gt;正常情况下，ecFlow 任务的正常状态变化如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;排队（queued）-&amp;gt; 提交（submitted）-&amp;gt; 运行（active）-&amp;gt; 完成（complete）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当出错时，节点会进入&lt;strong&gt;出错&lt;/strong&gt;（aborted）状态。另外，
节点也可以被&lt;strong&gt;挂起&lt;/strong&gt;（suspended），阻止任务运行。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/workflow-log/ecflow-log-parser/status/ecflow-node-status.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ecFlow 中任务（Task）节点的状态变化&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;节点状态的每次变化，都会在 ecFlow 日志中记录相应的条目。
容器节点（Family 和 Suite）的状态是其所有子节点的状态种类中权重最大的状态。
所以 Task 节点状态变化通常会导致一系列父节点状态改变。
表现在日志中就是有一串关联的节点状态同时改变，如下所示&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[11:08:52 3.6.2020] chd:init /grapes_tym/grapes_d01/06/prods/grib2/grib2_003
LOG:[11:08:52 3.6.2020] active: /grapes_tym/grapes_d01/06/prods/grib2/grib2_003
LOG:[11:08:52 3.6.2020] active: /grapes_tym/grapes_d01/06/prods/grib2
LOG:[11:08:52 3.6.2020] active: /grapes_tym/grapes_d01/06/prods
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;权重列表如下，其中最后两个状态仅限于 ecFlow 服务节点。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;状态&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Unknown&lt;/td&gt;
					&lt;td&gt;权重最小&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Complete&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Queued&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Submitted&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Active&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Suspend&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Aborted&lt;/td&gt;
					&lt;td&gt;对于 task 是最重要的状态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Shutdown&lt;/td&gt;
					&lt;td&gt;仅限于 ecFlow 服务节点&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Halted&lt;/td&gt;
					&lt;td&gt;最重要的状态，仅限于 ecFlow 服务节点&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="日志示例"&gt;日志示例&lt;/h2&gt;
&lt;p&gt;下面举例说明各个状态的日志。&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志解析 - 通用字段</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/</link><pubDate>Tue, 16 Jun 2020 22:42:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-16-ecflow-notebook-parse-ecflow-log-common/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-15-ecflow-notebook-ecflow-log-type/"&gt;ecFlow笔记：ecFlow日志分类&lt;/a&gt;》介绍 ecFlow 日志的几种常见类型。
本文介绍如何解析日志条目的通用字段。&lt;/p&gt;
&lt;p&gt;本文代码均来自 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h2 id="通用结构"&gt;通用结构&lt;/h2&gt;
&lt;p&gt;ecFlow 日志条目有相似的结构。&lt;/p&gt;
&lt;p&gt;下面是 4 种主要类型的日志条目示例，并用不同的颜色区分不同的字段。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/workflow-log/ecflow-log-parser/common-structure-example.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ecFlow 日志字段结构示例&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;可以看到，所有条目的开头都有相同格式，包含日志级别（Log type / Log level）和时间（Datetime）两个字段。
而不同类型的日志由 Command（Event Type）字段区分。
大部分日志包含节点路径（Node path）。
少部分日志包含与命令相关的附加信息（Additional Information）。&lt;/p&gt;
&lt;p&gt;ecFlow 日志条目的通用对象包含如下字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;日志级别（Log Type）&lt;/li&gt;
&lt;li&gt;日期（Date）&lt;/li&gt;
&lt;li&gt;时间（Time）&lt;/li&gt;
&lt;li&gt;日志事件（Event）&lt;/li&gt;
&lt;li&gt;节点路径（Node Path）&lt;/li&gt;
&lt;li&gt;附加信息（Additional Information）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同类型的日志对象可有自己特定的字段。
如下图所示&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/workflow-log/ecflow-log-parser/record-structure-v2.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ecFlow 日志条目对象&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="通用解析"&gt;通用解析&lt;/h2&gt;
&lt;p&gt;ecFlow 的所有日志，都以日志层次和时间开头。所以解析日志时首先寻找 &lt;code&gt;:&lt;/code&gt; 符号，获取日志层次；再寻找 &lt;code&gt;]&lt;/code&gt; 符号，获取日志的日期和时间。&lt;/p&gt;
&lt;p&gt;然后根据 &lt;code&gt;] &lt;/code&gt; 后续的少量字符来判断日志的类型。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;] &lt;/code&gt; 后面如果有一个空格，表明条目是状态变化记录。例如&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;LOG:[17:24:11 8.6.2020] complete: /grapes_tym/grapes_d01/12/prods/plot/plot_036
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;] &lt;/code&gt; 后面是 &lt;code&gt;chd:&lt;/code&gt;，表明条目是 child 命令记录。例如&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[17:24:11 8.6.2020] chd:complete /grapes_tym/grapes_d01/12/prods/plot/plot_036
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;] &lt;/code&gt; 后面是 &lt;code&gt;--&lt;/code&gt;，表明条目是 client 命令记录。例如&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志分类</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-15-ecflow-notebook-ecflow-log-type/</link><pubDate>Mon, 15 Jun 2020 22:38:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-15-ecflow-notebook-ecflow-log-type/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/06/2020-06-14-ecflow-notebook-ecflow-log-introduction/"&gt;ecFlow笔记：ecFlow日志简介&lt;/a&gt;》介绍 ecFlow 日志条目的格式和含义，并提到日志条目中的 command 字段用于区分不同类型的日志。&lt;/p&gt;
&lt;p&gt;本文介绍 ecFlow 日志中常见的条目类型。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;下面 4 行日志条目分别代表 4 种常见的日志类型。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[12:20:30 15.6.2020] svr:check_pt in 0 seconds
MSG:[12:20:32 15.6.2020] --sync_full=0 :monitor
MSG:[12:20:39 15.6.2020] chd:init /grapes_meso_3km_post/06/upload/tograph/meso_area_radar/radar_reflectivity/plot_hour_021
LOG:[12:20:39 15.6.2020] active: /grapes_meso_3km_post/06/upload/tograph/meso_area_radar/radar_reflectivity/plot_hour_021
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;第 1 行：服务端记录，表示 ecFlow 在进行 checkpoint 归档&lt;/li&gt;
&lt;li&gt;第 2 行：client 命令记录，表示 monitor 用户与 ecFlow 服务进行同步&lt;/li&gt;
&lt;li&gt;第 3 行：child 命令记录：表示任务节点执行 &lt;code&gt;ecflow_client --init&lt;/code&gt; 命令&lt;/li&gt;
&lt;li&gt;第 4 行：状态变化记录：表示任务节点运行状态变为 active&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面分别介绍这几种日志类型。&lt;/p&gt;
&lt;h2 id="状态变化记录"&gt;状态变化记录&lt;/h2&gt;
&lt;p&gt;状态变化记录（&lt;code&gt;StatusLogRecord&lt;/code&gt;）是最常用的日志条目，记录 ecFlow 中每个节点的状态变化。&lt;/p&gt;
&lt;p&gt;节点状态主要包括（请参考 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-model"&gt;nwpc-workflow-model&lt;/a&gt; 的 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-model/blob/d079c1453d5764b2f0782b21ef458cf55e44cc5a/nwpc_workflow_model/node_status.py#L5"&gt;NodeStatus&lt;/a&gt; 类）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;queued&lt;/code&gt;：排队&lt;/li&gt;
&lt;li&gt;&lt;code&gt;submitted&lt;/code&gt;：提交&lt;/li&gt;
&lt;li&gt;&lt;code&gt;active&lt;/code&gt;：运行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete&lt;/code&gt;：完成&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aborted&lt;/code&gt;：出错&lt;/li&gt;
&lt;li&gt;&lt;code&gt;suspended&lt;/code&gt;：挂起&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;状态变化记录的 command 字段就是上面的状态&lt;/p&gt;</description></item><item><title>ecFlow笔记：ecFlow日志简介</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-14-ecflow-notebook-ecflow-log-introduction/</link><pubDate>Sun, 14 Jun 2020 22:19:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-14-ecflow-notebook-ecflow-log-introduction/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 NWPC 工作流日志工具的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文主要对 ecFlow 的日志进行简要介绍。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;NWPC/CMA 在 2018 年将数值预报业务系统从 IBM 迁移到 CMA-PI 的同时，将原有的工作流软件 SMS 升级为 ecFlow。
笔者在使用 SMS 的期间就已经开发 SMS 日志分析工具，并完成单位的青年基金课题。在切换到 ecFlow 后持续升级该工具，形成一系列正在开发中的 ecFlow 日志工具：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ecFlow 日志模型&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-collector"&gt;nwpc-oper/nwpc-workflow-log-collector&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ecFlow 日志收集工具&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-tool"&gt;nwpc-oper/nwpc-workflow-log-tool&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ecFlow 日志分析工具&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-processor"&gt;nwpc-oper/nwpc-workflow-log-processor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ecFlow 日志批量处理工具&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NWPC 工作流日志工具正在升级开发中，笔者会持续修改历史代码。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;ecFlow 的日志文件包含 ecFlow 服务的所有操作，并显示诸如 halt，shutdown 等信息。
如下所示：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[13:09:20 14.5.2020] chd:init /gmf_grapes_gfs_v2.4/06/dasrefresh
LOG:[13:09:20 14.5.2020] active: /gmf_grapes_gfs_v2.4/06/dasrefresh
LOG:[13:09:20 14.5.2020] active: /gmf_grapes_gfs_v2.4/06
LOG:[13:09:20 14.5.2020] active: /gmf_grapes_gfs_v2.4
LOG:[13:09:20 14.5.2020] active: /
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;日志文件是一个纯文本文件，可以被其他程序处理。&lt;/p&gt;
&lt;p&gt;例如，ecflow_ui 在 timeline 窗口中读取日志文件并显示统计信息。&lt;/p&gt;</description></item><item><title>NWPC笔记：GRAPES_MESO v5.0 后处理系统运行报告</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-13-nwpc-notebook-grapes-meso-3km-post-system-report/</link><pubDate>Sat, 13 Jun 2020 19:34:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-13-nwpc-notebook-grapes-meso-3km-post-system-report/</guid><description>&lt;p&gt;GRAPES_MESO v5.0 系统将于最近正式业务化运行。
本文是为后处理系统准备的运行报告。
虽然最终没能放入到正式的运行报告中，但也可以作为近一个月时间升级工作的纪念，为 GRAPES_MESO v5.0 后处理系统升级工作画上句号。
终于可以将精力专注到投入产出比更高的任务中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GRAPES_MESO v5.0 后处理系统包含两个子系统：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grapes_meso_3km_post&lt;/code&gt;：数据产品制作和少量图片产品制作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grapes_meso_3km_graph&lt;/code&gt;：图片产品制作子系统，从 GRAPES MESO 10km 系统移植而来&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="技术细节"&gt;技术细节&lt;/h2&gt;
&lt;p&gt;本文不介绍如何构建后处理系统，系统建设的相关技术细节请参考以下文章：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-08-nwpc-system-notebook-build-image-production-suite/"&gt;NWPC笔记：构建图片产品制作系统&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-31-nwpc-notebook-build-image-production-script/"&gt;NWPC笔记：构建图片产品制作脚本&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="系统运行情况"&gt;系统运行情况&lt;/h2&gt;
&lt;h3 id="系统运行调度时间"&gt;系统运行调度时间&lt;/h3&gt;
&lt;p&gt;grapes_meso_3km_post：模式积分完成后20分钟&lt;/p&gt;
&lt;p&gt;grapes_meso_3km_graph：post完成后15分钟。实际运行时间与设定的并发作业数量有关。&lt;/p&gt;
&lt;h3 id="模式运行耗时及资源使用情况"&gt;模式运行耗时及资源使用情况&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/run-time.png"&gt;
&lt;/figure&gt;

&lt;h2 id="系统目录结构"&gt;系统目录结构&lt;/h2&gt;
&lt;p&gt;后处理系统的目录由3部分组成，分别是程序源代码目录、ECFLOW 脚本目录和运行目录。
其中程序源代码目录包含转码程序、绘图脚本及其他需要使用到的程序。
ECFLOW 脚本目录用于 ECFLOW作业调度及运行。运行目录用于系统是实时运行。&lt;/p&gt;
&lt;p&gt;运行目录中每个时次使用独立的目录，保证多个时次可以同时运行。
后处理子系统中不同时效的数据产品在不同的目录中生成。
绘图子系统中每个时效的每个产品使用单独的子目录，保证所有图片绘制任务可以独立运行。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/grapes-meso-3km-post-directory.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;grapes_meso_3km_post 目录&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/grapes-meso-3km-graph-directory.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;grapes_meso_3km_graph 目录&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="系统运行流程"&gt;系统运行流程&lt;/h2&gt;
&lt;p&gt;后处理子系统实时检测模式输出的 modelvar 数据，转码生成原始分辨率 GRIB2 产品。
再驱动其他数据产品生成任务，和图片绘制任务。
绘图子系统实时检测后处理子系统生成的原始分辨率 GRIB2 产品，并根据已生成的 GRIB2 产品绘制相应时效的图片产品。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/meso-3km-2020-flow.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;后处理系统运行流程&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="系统各模块说明"&gt;系统各模块说明&lt;/h2&gt;
&lt;h3 id="grapes_meso_3km_post"&gt;grapes_meso_3km_post&lt;/h3&gt;
&lt;p&gt;该系统用于制作数据产品和部分图片产品，一天共运行8个时次，每个时次的模块相同，如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/post-cycle.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;grapes_meso_3km_post 单个时次模块&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id="initial"&gt;initial&lt;/h4&gt;
&lt;p&gt;检查模式输出的 modelvar 文件。该模块随整个时次一同启动。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/meso-3km-post/post-initial.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;initial 模块&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id="togrib2-模块"&gt;togrib2 模块&lt;/h4&gt;
&lt;p&gt;生成包括 GRIB2 格式在内的数据产品。该模块随着 initial 模块检测 modelvar 的进度而逐步运行各个时效。&lt;/p&gt;</description></item><item><title>使用 Jupyter Widgets 构建简单的交互应用</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-12-build-simple-ui-using-jupyter-widgets/</link><pubDate>Fri, 12 Jun 2020 10:31:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-12-build-simple-ui-using-jupyter-widgets/</guid><description>&lt;p&gt;在之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/01/2020-01-16-show-ncl-plot-in-jupyter-notebook/"&gt;使用Jupyter Notebook显示NCL绘图&lt;/a&gt;》中介绍如何将 NWPC 业务系统的 NCL 绘图脚本集成到 Jupyter Notebook 中。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;show_plot&lt;/code&gt; 函数在 Notebook 中显示图片。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_graphics.systems.grapes_gfs_gmf &lt;span style="color:#f92672"&gt;import&lt;/span&gt; show_plot
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show_plot(&lt;span style="color:#e6db74"&gt;&amp;#34;pwat_sfc_an_aea&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;2020011300&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;24h&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;函数调用的方式不够方便，本文介绍使用 Jupyter Wdigets 即 ipywidgets 包封装上述的函数调用，构建简单的交互应用。&lt;/p&gt;
&lt;h2 id="控件"&gt;控件&lt;/h2&gt;
&lt;p&gt;ipywidgets 包为开发人员提供使用 Python 代码生成 Web 控件的功能，提供大量常用的 Web 交互部件。&lt;/p&gt;
&lt;p&gt;基本用法请参考官方文档《&lt;a href="https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Basics.html"&gt;Simple Widget Introduction&lt;/a&gt;》，不再介绍。&lt;/p&gt;
&lt;p&gt;针对本文封装函数调用的目标，我们需要从控件中获取参数值。&lt;/p&gt;
&lt;h3 id="下拉菜单"&gt;下拉菜单&lt;/h3&gt;
&lt;p&gt;图片类型使用下拉菜单。
让我们首先创建一个下拉菜单 &lt;code&gt;Dropdown&lt;/code&gt;，使用 &lt;code&gt;plotters&lt;/code&gt; 的 key 列表作为值选项。
直接创建的控件不会显示在输出结果中，需要调用 ipython 的 &lt;code&gt;display&lt;/code&gt; 函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot_type_options &lt;span style="color:#f92672"&gt;=&lt;/span&gt; widgets&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Dropdown(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options&lt;span style="color:#f92672"&gt;=&lt;/span&gt;list(plotters&lt;span style="color:#f92672"&gt;.&lt;/span&gt;keys()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; value&lt;span style="color:#f92672"&gt;=&lt;/span&gt;list(plotters&lt;span style="color:#f92672"&gt;.&lt;/span&gt;keys())[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Plot Type:&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; disabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;display(plot_type_options)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc-graphics/widgets/plot-type.png"&gt;
&lt;/figure&gt;

&lt;p&gt;使用控件的 &lt;code&gt;.value&lt;/code&gt; 属性获取用户选择的值&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot_type_options&lt;span style="color:#f92672"&gt;.&lt;/span&gt;value
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;hgt_p500_mslp_sfc_fc_aeua
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;另外起报时次（00,06,12,18）也使用下拉菜单，不再介绍。&lt;/p&gt;</description></item><item><title>PyTorch教程：训练分类器</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-09-pytorch-tutorials-blitz-training-a-classifier/</link><pubDate>Tue, 09 Jun 2020 22:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-09-pytorch-tutorials-blitz-training-a-classifier/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自Pytorch官方文档《&lt;a href="https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html"&gt;DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;就是这个。您已经了解了如何定义神经网络，计算损耗并更新网络的权重。&lt;/p&gt;
&lt;p&gt;现在您可能在想，&lt;/p&gt;
&lt;h2 id="数据呢"&gt;数据呢？&lt;/h2&gt;
&lt;p&gt;通常，当您必须处理图像，文本，音频或视频数据时，可以使用标准 python 包将数据加载到 numpy 数组中。
然后，您可以将此数组转换为 &lt;code&gt;torch.*Tensor&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于图像，有用的软件包如 Pillow，OpenCV&lt;/li&gt;
&lt;li&gt;对于音频，请使用 scipy 和 librosa 等软件包&lt;/li&gt;
&lt;li&gt;对于文本，基于原始 Python 或 Cython 加载，或者 NLTK 和 SpaCy 很有用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;专门针对视觉，我们创建了一个名为 &lt;code&gt;torchvision&lt;/code&gt; 的程序包，其中包含用于常见数据集（例如 Imagenet，CIFAR10，MNIST等）的数据加载器，以及用于图像（即 &lt;code&gt;torchvision.datasets&lt;/code&gt; 和 &lt;code&gt;torch.utils.data.DataLoader&lt;/code&gt;）的数据转换器。&lt;/p&gt;
&lt;p&gt;这提供了极大的便利，并且避免了编写样板代码。&lt;/p&gt;
&lt;p&gt;在本教程中，我们将使用 CIFAR10 数据集，
包含以下类别： ‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。
CIFAR-10 中的图像尺寸为 3x32x32，即尺寸为 32x32 像素的 3 通道彩色图像。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/pytorch/tutorial/blitz/cifar10.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;cifar10&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="训练图片分类器"&gt;训练图片分类器&lt;/h2&gt;
&lt;p&gt;我们将按顺序执行以下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;torchvision&lt;/code&gt; 加载和标准化 CIFAR10 训练和测试数据集&lt;/li&gt;
&lt;li&gt;定义卷积神经网络&lt;/li&gt;
&lt;li&gt;定义损失函数&lt;/li&gt;
&lt;li&gt;根据训练数据训练网络&lt;/li&gt;
&lt;li&gt;在测试数据上测试网络&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="1-加载和标准化-cifar10"&gt;1. 加载和标准化 CIFAR10&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;torchvision&lt;/code&gt;，加载 CIFAR10 非常容易。&lt;/p&gt;</description></item><item><title>PyTorch教程：神经网络</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-08-pytorch-tutorials-blitz-neural-networks/</link><pubDate>Mon, 08 Jun 2020 20:47:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-08-pytorch-tutorials-blitz-neural-networks/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自Pytorch官方文档《&lt;a href="https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html"&gt;DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以使用 &lt;code&gt;torch.nn&lt;/code&gt; 包构建神经网络。&lt;/p&gt;
&lt;p&gt;现在您已经了解了 &lt;code&gt;autograd&lt;/code&gt;，&lt;code&gt;nn&lt;/code&gt; 依靠 &lt;code&gt;autograd&lt;/code&gt; 定义模型并对其进行区分。
&lt;code&gt;nn.Module&lt;/code&gt; 包含图层，以及返回 &lt;code&gt;output&lt;/code&gt; 的方法 &lt;code&gt;forward(input)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如，查看以下对数字图像进行分类的网络：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/pytorch/tutorial/blitz/covnet.png" alt="convnet"&gt;&lt;/p&gt;
&lt;p&gt;convnet&lt;/p&gt;
&lt;p&gt;这是一个简单的前馈网络。
它获取输入，将其一层又一层地馈入，然后最终给出输出。&lt;/p&gt;
&lt;p&gt;神经网络的典型训练过程如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定义具有一些可学习参数（或权重）的神经网络&lt;/li&gt;
&lt;li&gt;遍历输入数据集&lt;/li&gt;
&lt;li&gt;通过网络处理输入&lt;/li&gt;
&lt;li&gt;计算损失（输出离正确有多远）&lt;/li&gt;
&lt;li&gt;将梯度传播回网络参数&lt;/li&gt;
&lt;li&gt;更新网络的权重，通常使用简单的更新规则：&lt;code&gt;weight = weight - learning_rate * gradient&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;下面的图片来自 &lt;a href="https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53"&gt;A Comprehensive Guide to Convolutional Neural Networks — the ELI5 way&lt;/a&gt;，能更清晰地展示整个网络。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/pytorch/tutorial/blitz/convnet-2.jpeg" alt=""&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="定义网络"&gt;定义网络&lt;/h2&gt;
&lt;p&gt;让我们定义这个网络&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; torch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; torch.nn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; nn
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; torch.nn.functional &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; F
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Net&lt;/span&gt;(nn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Module):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; super(Net, self)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 1个输入图片通道，6个输出通道，3x3 平方卷积核&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conv1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Conv2d(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conv2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Conv2d(&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 仿射操作: y = Wx + b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fc1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Linear(&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# 图片维度 6*6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fc2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Linear(&lt;span style="color:#ae81ff"&gt;120&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;84&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fc3 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Linear(&lt;span style="color:#ae81ff"&gt;84&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;forward&lt;/span&gt;(self, x):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Max pooling over a (2, 2) window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; F&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max_pool2d(F&lt;span style="color:#f92672"&gt;.&lt;/span&gt;relu(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conv1(x)), (&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 如果尺寸为正方形，则只能指定一个数字&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; F&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max_pool2d(F&lt;span style="color:#f92672"&gt;.&lt;/span&gt;relu(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;conv2(x)), &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; x&lt;span style="color:#f92672"&gt;.&lt;/span&gt;view(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;num_flat_features(x))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; F&lt;span style="color:#f92672"&gt;.&lt;/span&gt;relu(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fc1(x))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; F&lt;span style="color:#f92672"&gt;.&lt;/span&gt;relu(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fc2(x))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fc3(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;num_flat_features&lt;/span&gt;(self, x):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; x&lt;span style="color:#f92672"&gt;.&lt;/span&gt;size()[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:] &lt;span style="color:#75715e"&gt;# 除 batch 维度外的所有维度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num_features &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; s &lt;span style="color:#f92672"&gt;in&lt;/span&gt; size:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num_features &lt;span style="color:#f92672"&gt;*=&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; num_features
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;net &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Net()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;net
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Net(
 (conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
 (conv2): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1))
 (fc1): Linear(in_features=576, out_features=120, bias=True)
 (fc2): Linear(in_features=120, out_features=84, bias=True)
 (fc3): Linear(in_features=84, out_features=10, bias=True)
)
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;最大池化：Max pooling&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>PyTorch教程：autograd - 自动微分</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-07-pytorch-tutorials-blitz-autograd-automatic-differentiation/</link><pubDate>Sun, 07 Jun 2020 22:15:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-07-pytorch-tutorials-blitz-autograd-automatic-differentiation/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自Pytorch官方文档《&lt;a href="https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html"&gt;DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PyTorch 中所有神经网络的核心是 &lt;code&gt;autograd&lt;/code&gt; 软件包。
让我们先简要地介绍一下，然后再训练第一个神经网络。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;autograd&lt;/code&gt; 软件包为 Tensor 上的所有操作提供自动微分。
它是一个按运行定义的框架，这意味着您的反向传播（backprop）是由代码的运行方式定义的，并且每次迭代都可以不同。&lt;/p&gt;
&lt;p&gt;让我们通过一些示例以更简单的方式展示这一点。&lt;/p&gt;
&lt;h2 id="tensor"&gt;Tensor&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;torch.Tensor&lt;/code&gt; 是程序包的中心类。
如果将其属性 &lt;code&gt;.requires_grad&lt;/code&gt; 设置为 &lt;code&gt;True&lt;/code&gt;，它将开始跟踪对其的所有操作。
完成计算后，可以调用 &lt;code&gt;.backward()&lt;/code&gt; 并自动计算所有梯度。
该 tensor 的梯度将累积到 &lt;code&gt;.grad&lt;/code&gt; 属性中。&lt;/p&gt;
&lt;p&gt;要停止 tensor 跟踪历史记录，可以调用 &lt;code&gt;.detach()&lt;/code&gt; 将其与计算历史记录分离，并防止跟踪将来的计算。&lt;/p&gt;
&lt;p&gt;为了防止跟踪历史记录（和使用内存），您还可以使用 &lt;code&gt;with torch.no_grad()：&lt;/code&gt; 包装代码块。
这在评估模型时特别有用，因为模型可能具有可训练且 &lt;code&gt;require_grad=True&lt;/code&gt; 的参数，但我们不需要梯度。&lt;/p&gt;
&lt;p&gt;还有另外一个类对 autograd 实现非常重要：&lt;code&gt;Function&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Tensor&lt;/code&gt; 和 &lt;code&gt;Function&lt;/code&gt; 相互连接并建立一个无环图，该图对完整的计算历史进行编码。
每个 tensor 都有一个 &lt;code&gt;.grad_fn&lt;/code&gt; 属性，该属性引用创建了 &lt;code&gt;Tensor&lt;/code&gt; 的 &lt;code&gt;Function&lt;/code&gt;（用户创建的 Tensors 除外 —— 它们的 &lt;code&gt;grad_fn is None&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;如果要计算导数，可以在 &lt;code&gt;Tensor&lt;/code&gt; 上调用 &lt;code&gt;.backward()&lt;/code&gt;。
如果 &lt;code&gt;Tensor&lt;/code&gt; 是标量（即，它保存一个元素），则无需为 &lt;code&gt;backward()&lt;/code&gt; 指定任何参数，但是，如果 Tensor 具有更多元素，则需要指定一个匹配形状的 tensor 作为 &lt;code&gt;gradient&lt;/code&gt; 参数 。&lt;/p&gt;</description></item><item><title>PyTorch教程：什么是PyTorch</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-06-pytorch-tutorials-blitz-what-is-pytorch/</link><pubDate>Sat, 06 Jun 2020 20:52:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-06-pytorch-tutorials-blitz-what-is-pytorch/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自Pytorch官方文档《&lt;a href="https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html"&gt;DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pytorch 是基于 Python 的科学计算包，面向两类用户：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;替代 NumPy 以使用 GPUs 的功能&lt;/li&gt;
&lt;li&gt;提供最大灵活性和速度的深度学习研究平台&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="开始"&gt;开始&lt;/h2&gt;
&lt;h3 id="tensors"&gt;Tensors&lt;/h3&gt;
&lt;p&gt;Tensors 与 NumPy 的 ndarray 相似，此外，Tensor 也可以在 GPU 上使用以加速计算。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; torch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;声明了一个未初始化的矩阵，但在使用前不包含确定的已知值。
创建未初始化的矩阵时，当时分配的内存中的任何值都将显示为初始值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;构造一个未初始化的5x3矩阵：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; torch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;empty(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;tensor([[6.0426e-15, 7.4969e-43, 6.0426e-15],
 [7.4969e-43, 6.0414e-15, 7.4969e-43],
 [6.0414e-15, 7.4969e-43, 6.0437e-15],
 [7.4969e-43, 6.0437e-15, 7.4969e-43],
 [6.0423e-15, 7.4969e-43, 6.0423e-15]])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;构造一个随机初始化的矩阵：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; torch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rand(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;tensor([[0.0816, 0.3339, 0.7984],
 [0.0912, 0.8468, 0.7928],
 [0.5448, 0.3244, 0.7647],
 [0.7238, 0.5896, 0.2261],
 [0.2130, 0.9357, 0.5388]])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;构造一个填充零且 dtype 是 long 的矩阵：&lt;/p&gt;</description></item><item><title>Bokeh教程：运行Bokeh应用</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-04-bokeh-tutorial-running-bokeh-application/</link><pubDate>Thu, 04 Jun 2020 20:38:23 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-04-bokeh-tutorial-running-bokeh-application/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bokeh 的体系结构是在 Python 中创建高级 “模型对象”（表示 plots, ranges, axes, glyphs 等），然后转换为客户端库 BokehJS 使用的 JSON 格式。
使用 Bokeh 服务器，可以使 python 和浏览器中的“模型对象”彼此保持同步，从而创建强大的功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;利用 Python 的全部功能通过计算或查询来响应浏览器中生成的 UI 和工具事件&lt;/li&gt;
&lt;li&gt;在浏览器中自动推送更新用户界面（即控件或绘图）&lt;/li&gt;
&lt;li&gt;使用定期，超时和异步回调来驱动流更新&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;这种在 python 和浏览器之间进行同步的功能是 Bokeh Server 的主要目的。&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="notebook-中的-bokeh-应用"&gt;Notebook 中的 Bokeh 应用&lt;/h2&gt;
&lt;p&gt;在 Notebook 中嵌入 Bokeh 应用程序的最简单方法是创建一个函数 &lt;code&gt;modify_doc(doc)&lt;/code&gt;，该功能创建Bokeh 内容并将其添加到文档中。
这个函数可以传递给 &lt;code&gt;show&lt;/code&gt;，并且该函数定义的应用将内联显示。
下面是一个简短的完整示例&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.layouts &lt;span style="color:#f92672"&gt;import&lt;/span&gt; column
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.models &lt;span style="color:#f92672"&gt;import&lt;/span&gt; TextInput, Button, Paragraph
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;modify_doc&lt;/span&gt;(doc):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 创建一些控件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Button(label&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Say HI&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; input &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TextInput(value&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Bokeh&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Paragraph()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 为控件添加回调函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;update&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; output&lt;span style="color:#f92672"&gt;.&lt;/span&gt;text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello, &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; input&lt;span style="color:#f92672"&gt;.&lt;/span&gt;value
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; button&lt;span style="color:#f92672"&gt;.&lt;/span&gt;on_click(update)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 为所有对象创建布局&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; layout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; column(button, input, output)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 将布局添加到当前的文档&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; doc&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_root(layout)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 在笔记本中，只需传递定义应用的函数即可显示&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 您可能需要提供笔记本网址，例如，notebook_url=&amp;#34;http://localhost:8889&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(modify_doc) 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/application/notebook-widget.png"&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;练习&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Bokeh教程：导出和嵌入</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-03-bokeh-tutorial-exporting-and-embending/</link><pubDate>Wed, 03 Jun 2020 22:13:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-03-bokeh-tutorial-exporting-and-embending/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;到目前为止，我们已经看到如何在 Jupyter 中直接内联生成交互式 Bokeh 输出。
也可以在其他上下文中（例如独立 HTML 文件或 Jinja 模板）嵌入交互式 Bokeh 图和布局。
此外，Bokeh 可以将图导出为静态（非交互式）PNG 和 SVG 格式。&lt;/p&gt;
&lt;p&gt;我们将在本章中探讨所有这些可能性。
首先，我们进行常规导入。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;并加载一些将在本章中使用的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.sampledata.stocks &lt;span style="color:#f92672"&gt;import&lt;/span&gt; AAPL
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame(AAPL)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df[&lt;span style="color:#e6db74"&gt;&amp;#39;date&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(df[&lt;span style="color:#e6db74"&gt;&amp;#39;date&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/exporting/stocks-df-head.png"&gt;
&lt;/figure&gt;

&lt;h2 id="嵌入交互内容"&gt;嵌入交互内容&lt;/h2&gt;
&lt;p&gt;首先，我们将研究在各种情况下嵌入实时交互 Bokeh 输出的不同方式。&lt;/p&gt;
&lt;h3 id="在-notebook-中显示"&gt;在 Notebook 中显示&lt;/h3&gt;
&lt;p&gt;正如我们已经看到的，嵌入 Bokeh 输出的第一种方法是在 Jupyter Notebook 中。
提醒一下，下面的单元格将生成一个内联图作为输出，因为我们执行了上面的 &lt;code&gt;output_notebook&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;800&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_axis_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;datetime&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;line(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#39;date&amp;#39;&lt;/span&gt;], 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#39;close&amp;#39;&lt;/span&gt;], 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;navy&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alpha&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(p)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/exporting/notebook.png"&gt;
&lt;/figure&gt;

&lt;h3 id="保存成-html-文件"&gt;保存成 HTML 文件&lt;/h3&gt;
&lt;p&gt;生成包含 Bokeh 内容的独立 HTML 脚本通常也很有用。
这是通过调用 &lt;code&gt;output_file(...)&lt;/code&gt; 函数来完成的。
在标准 Python 脚本中执行此操作特别常见，但是这里我们看到也可以在 Notebook 中使用。&lt;/p&gt;</description></item><item><title>Bokeh教程：图和网络图</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-02-bokeh-tutorial-graph-and-network-plots/</link><pubDate>Tue, 02 Jun 2020 21:19:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-02-bokeh-tutorial-graph-and-network-plots/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本章将介绍如何使用 NetwortkX 在 Bokeh 中绘制网络节点/链接图。
有关从底层创建图形渲染器的信息，请参见&lt;a href="https://docs.bokeh.org/en/latest/docs/user_guide/graph.html"&gt;可视化网络图&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="从-networkx-绘图"&gt;从 NetworkX 绘图&lt;/h2&gt;
&lt;p&gt;用 Bokeh 绘制网络图的最简单方法是使用 &lt;code&gt;from_networkx&lt;/code&gt; 函数。
该函数接受任何 &lt;code&gt;NetworkX&lt;/code&gt; 图形，并返回可以添加到绘图中的 Bokeh &lt;code&gt;GraphRenderer&lt;/code&gt;。 &lt;code&gt;GraphRenderer&lt;/code&gt; 具有 &lt;code&gt;node_renderer&lt;/code&gt; 和 &lt;code&gt;edge_renderer&lt;/code&gt; 属性，这些属性包含分别绘制节点和边的 Bokeh 渲染器。&lt;/p&gt;
&lt;p&gt;下面的示例显示了 &lt;code&gt;nx.desargues_graph()&lt;/code&gt; 的 Bokeh 绘图，它设置了一些节点和边属性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; networkx &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; nx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.models &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Range1d, Plot
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; from_networkx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;G &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nx&lt;span style="color:#f92672"&gt;.&lt;/span&gt;desargues_graph()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 我们可以在这里使用 figure，但不要所有的轴和标题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Plot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Range1d(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Range1d(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 使用 nx.spring_layout 从 NetworkX 输入创建 Bokeh 绘图&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;graph &lt;span style="color:#f92672"&gt;=&lt;/span&gt; from_networkx(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; G, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nx&lt;span style="color:#f92672"&gt;.&lt;/span&gt;spring_layout, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; scale&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1.8&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; center&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;renderers&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(graph)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 设置一些默认的节点字形（圆形）属性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;graph&lt;span style="color:#f92672"&gt;.&lt;/span&gt;node_renderer&lt;span style="color:#f92672"&gt;.&lt;/span&gt;glyph&lt;span style="color:#f92672"&gt;.&lt;/span&gt;update(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fill_color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 设置一些边缘属性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;graph&lt;span style="color:#f92672"&gt;.&lt;/span&gt;edge_renderer&lt;span style="color:#f92672"&gt;.&lt;/span&gt;glyph&lt;span style="color:#f92672"&gt;.&lt;/span&gt;line_dash &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(plot)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/graph/networkx.png"&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;练习&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Bokeh教程：条形图和分类数据绘图</title><link>https://blog.perillaroc.wang/post/2020/06/2020-06-01-bokeh-tutorial-bar-and-categorical-data-plots/</link><pubDate>Mon, 01 Jun 2020 22:16:44 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/06/2020-06-01-bokeh-tutorial-bar-and-categorical-data-plots/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="基本条形图"&gt;基本条形图&lt;/h2&gt;
&lt;p&gt;条形图是常见且重要的绘图类型。
通过 Bokeh，可以轻松创建各种堆积或嵌套的条形图，并通常处理分类数据。&lt;/p&gt;
&lt;p&gt;下面的示例显示了一个简单的条形图，它使用 &lt;code&gt;vbar&lt;/code&gt; 方法创建，用于绘制垂直条形图。
（有一个相应的 &lt;code&gt;hbar&lt;/code&gt; 对应水平条。）
我们还设置了一些绘图属性以使图表看起来更好，有关视觉属性的信息，请参见《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-12-bokeh-tutorial-style-and-theming/"&gt;Bokeh教程：样式和主题&lt;/a&gt;》。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 下面是分类数值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fruits &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Apples&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Pears&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Nectarines&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Plums&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Grapes&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Strawberries&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 将 x_range 设置为上面的分类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;fruits, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Fruit Counts&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 分类数据同样可以用于坐标&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;vbar(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;fruits, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; top&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;], 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 设置属性，让绘图更美观&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;xgrid&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_line_color &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;y_range&lt;span style="color:#f92672"&gt;.&lt;/span&gt;start &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(p)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/bar/basic-bar.png"&gt;
&lt;/figure&gt;

&lt;p&gt;当我们想创建一个具有分类范围的图时，我们将分类值的有序列表传递给 &lt;code&gt;figure&lt;/code&gt;，例如 &lt;code&gt;x_range = ['a', 'b', 'c']&lt;/code&gt;。
在上面的图中，我们将水果列表传递给 &lt;code&gt;x_range&lt;/code&gt;，我们可以看到这些水果被设置为 x 轴。&lt;/p&gt;</description></item><item><title>NWPC笔记：构建图片产品制作脚本</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-31-nwpc-notebook-build-image-production-script/</link><pubDate>Sun, 31 May 2020 16:10:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-31-nwpc-notebook-build-image-production-script/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-08-nwpc-system-notebook-build-image-production-suite/"&gt;NWPC笔记：构建图片产品制作系统&lt;/a&gt;》介绍如何使用 ecFlow 构建图片产品制作系统，主要侧重在后处理系统的流程设计方面，即如何使用 ecFlow 的 Python API 构建系统流程。&lt;/p&gt;
&lt;p&gt;本文进一步介绍如何设计图片产品制作任务的脚本执行逻辑，方便快速添加新的绘图任务。&lt;/p&gt;
&lt;h2 id="图片产品制作"&gt;图片产品制作&lt;/h2&gt;
&lt;p&gt;NWPC 目前使用多种绘图软件完成业务产品的图形绘制，包括 GrADS、NCL、IDL 等。
我负责建设和维护的后处理系统主要使用 NCL 脚本绘制图片，具有相似的执行逻辑。&lt;/p&gt;
&lt;p&gt;NWPC 基于 NCL 开发绘图库 ncllib，提供通用的绘图功能。
所以业务系统直接调用的 NCL 脚本侧重在数据处理、样式选择等方面。
不过，我只关注绘图脚本向外部提供的接口。&lt;/p&gt;
&lt;p&gt;因为 NWPC 发布的每类图片产品的样式都是固定的，所以绘图样式被隐藏在 NCL 脚本中。
仅需要通过输入参数确定使用的数据，就可以完成绘图。&lt;/p&gt;
&lt;p&gt;业务系统中使用的 NCL 绘图脚本主要需要以下的参数用于确定使用的数据文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;时间信息，比如起报时次、预报时效等&lt;/li&gt;
&lt;li&gt;数据信息，比如数据目录、图片输出目录等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要注意的是，参数中并没有显示指定数据文件名，因为某些图形可能需要使用多个数据文件。
文件名信息被隐藏在 NCL 脚本中。&lt;/p&gt;
&lt;p&gt;注：文件名信息隐藏可以简化接口，但会影响绘图脚本的通用性。
可能也间接导致每个业务系统都有自己的绘图脚本（当然，还有其它更重要的原因）。&lt;/p&gt;
&lt;p&gt;获取输入参数有以下几种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令行参数&lt;/li&gt;
&lt;li&gt;环境变量&lt;/li&gt;
&lt;li&gt;参数文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，还包括从当前目录获取数据文件等隐含约定。&lt;/p&gt;
&lt;p&gt;图形绘制任务就是要按照 NCL 脚本的需求准备数据，设置需要的环境变量，准备参数文件，并调用 NCL 命令。&lt;/p&gt;
&lt;p&gt;下一节介绍在 GRAPES MESO 3KM/9KM 图片制作系统中使用的绘图任务设计方案。&lt;/p&gt;
&lt;h2 id="设计方案"&gt;设计方案&lt;/h2&gt;
&lt;p&gt;绘图任务一般包含下面几个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;准备数据&lt;/li&gt;
&lt;li&gt;准备绘图脚本运行环境&lt;/li&gt;
&lt;li&gt;执行绘图脚本&lt;/li&gt;
&lt;li&gt;分发绘图结果&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下图是 GRAPES MESO 3KM/9KM 图片制作系统中绘图任务的流程示意图。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/grapes-meso-3km-graph/graph-meso-3km-graph-plot-task-2.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES MESO 3KM/9KM GRAPH 系统绘图任务设计方案&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;系统中 &lt;code&gt;initial&lt;/code&gt; 任务负责监听数据产品制作系统生成的 GRIB2 文件。
每当检测到一个时效的文件已生成，该任务就在系统运行目录的 &lt;code&gt;data&lt;/code&gt; 目录下创建该文件的链接，并发出相应时效的 ecflow 事件。&lt;/p&gt;</description></item><item><title>ecFlow笔记：优化节点状态监控工具</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-29-ecflow-notebook-upgrade-ecflow-watchman/</link><pubDate>Fri, 29 May 2020 22:42:45 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-29-ecflow-notebook-upgrade-ecflow-watchman/</guid><description>&lt;p&gt;去年底，使用 ecFlow C++ API 开发了 ecFlow 节点状态监控工具 ecflow-watchman，并于今年 1 月替换原有基于 GO 开发的监控工具。
详情请阅读之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/01/2020-01-01-ecflow-notebook-ecflow-watchman-v2/"&gt;ecflow学习笔记：节点状态监控工具V2&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;但经过这几个月的运行，发现线程会在某些情况下退出，导致无法持续监控所有的 ecFlow 服务。
经排查发现，线程退出都在将状态数据保存到 Redis 数据库的地方。&lt;/p&gt;
&lt;p&gt;本文介绍如何避免 Redis 数据保存异常时退出，并介绍 ecflow-watchman 中对于 ecflow C++ API的异常处理。&lt;/p&gt;
&lt;h2 id="后台服务的异常处理"&gt;后台服务的异常处理&lt;/h2&gt;
&lt;p&gt;后台运行的服务一定要保证可用性，在任何情况下都能持续运行下去。&lt;/p&gt;
&lt;p&gt;节点状态监控工具会定时调用 ecFlow API 获取节点状态，向其他应用提供业务系统的准实时运行状态。
如果当前循环获取并保存状态出错，可以等到下一次循环再更新数据，基本不会影响整个工具的可用性。&lt;/p&gt;
&lt;p&gt;C++ 程序错误处理一般有两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;抛出异常&lt;/li&gt;
&lt;li&gt;返回错误码&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;分别对应保存状态和获取状态。
下面首先介绍保存 Redis 数据异常的处理，再介绍 ecFlow API 出错的处理。&lt;/p&gt;
&lt;h2 id="redis-plus-plus-异常处理"&gt;redis-plus-plus 异常处理&lt;/h2&gt;
&lt;p&gt;ecflow-watchman 使用 &lt;a href="https://github.com/sewenew/redis-plus-plus"&gt;sewenew/redis-plus-plus&lt;/a&gt; 将系统状态保存到 Redis 数据库。&lt;/p&gt;
&lt;p&gt;redis++ 库在出错时会抛出异常。比如在下面的代码中，将连接耗时限制为 1 秒钟。
存储操作执行超过 1 秒，会抛出 &lt;code&gt;TimeoutError&lt;/code&gt; 异常。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ConnectionOptions connection_options;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ...skip...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;connection_options.socket_timeout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;s;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;make_unique&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Redis&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(connection_options);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client_&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;set(key, value);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ecflow-watchman 在保存数据时会捕获 redis++ 库抛出的所有异常（定义在 &lt;code&gt;namespace sw::redis&lt;/code&gt; 中）。&lt;/p&gt;</description></item><item><title>NWPC笔记：优化模式输出文件检查模块</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-27-nwpc-notebook-check-output-to-get-model-progress/</link><pubDate>Wed, 27 May 2020 22:04:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-27-nwpc-notebook-check-output-to-get-model-progress/</guid><description>&lt;p&gt;去年的一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-08-07-nwpc-system-notebook-progress-for-forecast-task/"&gt;NWPC笔记：获取模式积分任务的执行进度&lt;/a&gt;》介绍 NWPC 数值预报业务系统中使用的积分进度跟踪方法。&lt;/p&gt;
&lt;p&gt;其中“检测数据文件输出”方法已应用于 GRAPES MESO 和 GRAPES TYM 等区域模式系统。
业务系统在检测到模式输出文件的同时，会将这些文件拷贝到临时归档目录（runtime archive）和 HPC 归档目录（archive）中。&lt;/p&gt;
&lt;p&gt;最近更新的 GRAPES TYM 系统将输出间隔由 3 小时缩短为 1 小时，并在 postvar 基础上增加模式面数据 modelvar 的输出，显著增加文件拷贝的数据量。
拷贝单个时效文件到两个归档目录耗时将近40秒，已超过模式输出文件的生成间隔（大概30秒），导致标尺 meter 失去指示意义，同时也严重滞后产品后处理任务。&lt;/p&gt;
&lt;p&gt;本文介绍如何对模式输出文件检查模块进行优化，使标尺指示的进度与模式积分进度相当。&lt;/p&gt;
&lt;h2 id="归档目录"&gt;归档目录&lt;/h2&gt;
&lt;p&gt;下面首先介绍数值预报业务系统的归档目录。&lt;/p&gt;
&lt;h3 id="临时归档目录"&gt;临时归档目录&lt;/h3&gt;
&lt;p&gt;直接使用模式输出目录中的数据就不需要拷贝数据，为什么需要将数据放到临时归档目录？&lt;/p&gt;
&lt;p&gt;NWPC 数值预报业务系统的数据存储目录如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/model-progress/model-output-directory.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;NWPC 数值预报业务系统数据存储目录&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;其中 Model Data Directory 是业务系统运行目录，实时生成的文件都保存在该目录下。&lt;/p&gt;
&lt;p&gt;runtime directory 是模式系统程序实际的运行目录。
一般不同时次在不同的目录中运行，例如 GRAPES MESO 系统由 4 个时次目录。
或者所有时次都在同一个目录中运行，例如 GRAPES TYM 系统只有一个运行目录。&lt;/p&gt;
&lt;p&gt;runtime archive directory 是模式数据的临时归档目录，一般只保留10天以内的数据。
archive directory 是在 HPC 归档目录下的在线目录，保存数据时间较长，模式积分输出的二进制数据可能会保存一个月。&lt;/p&gt;
&lt;p&gt;业务系统在每次使用运行目录进行积分前，一般会清空该目录下所有的文件。
在业务系统正常运行时，其实无论上面提到的哪种运行目录划分方式，都可以直接使用运行目录下的数据。
但业务系统要具备故障恢复的能力，在系统异常时，留有补救的手段。
比如发现前两天的某个产品没有正常生成，或者 FTP 传输异常，目标用户没有接收到，需要临时补做。
这就需要保留最近几天的模式原始输出数据，也是 runtime archive directory 存在的意义。&lt;/p&gt;</description></item><item><title>JupyterHub简单使用</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-26-getting-to-use-jupyterhub/</link><pubDate>Tue, 26 May 2020 22:17:01 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-26-getting-to-use-jupyterhub/</guid><description>&lt;p&gt;Jupyter Notebook 已成为数据分析的通用工具之一，在气象领域也有广泛的应用。&lt;/p&gt;
&lt;p&gt;之前我一直使用 Pycharm 调试 Python 程序，但今年开始使用 Jupyter Notebook 后，发现在数据探索和可视化等方面还是 Jupyter Notebook 更方便，也更轻量级。&lt;/p&gt;
&lt;p&gt;Jupyter Notebook 仅运行在单个用户账户下。如果想要向不同用户提供环境一致但相互独立的 Jupyter Notebook，可以使用 JupyterHub 工具。&lt;/p&gt;
&lt;p&gt;本文介绍 JupyterHub 的简单使用方法。&lt;/p&gt;
&lt;h2 id="快速开始"&gt;快速开始&lt;/h2&gt;
&lt;p&gt;使用 conda 安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conda install -c conda-forge jupyterhub
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conda install notebook
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在某个目录下启动 Hub 服务器&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jupyterhub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;浏览器访问 https://localhost:8000 ，使用系统密码登录。&lt;/p&gt;
&lt;p&gt;想要支持多个用户登录，必须使用管理员账户启动 &lt;code&gt;jupyterhub&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo jupyterhub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述启动的仅仅是一个简单的服务，最好使用配置文件设置一些参数。&lt;/p&gt;
&lt;h2 id="配置"&gt;配置&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;jupyterhub&lt;/code&gt; 生成默认的配置文件 &lt;code&gt;jupyterhub_config.py&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jupyterhub --generate-config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;默认的配置文件 &lt;code&gt;jupyterhub_config.py&lt;/code&gt; 中配置项都包含在注释中，例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## Duration (in seconds) to determine the number of active users.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#c.JupyterHub.active_user_window = 1800&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;指定配置文件启动 Hub 服务&lt;/p&gt;</description></item><item><title>视界：与NCEP运维的差距</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-25-view-ncep-central-opeartion/</link><pubDate>Mon, 25 May 2020 22:43:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-25-view-ncep-central-opeartion/</guid><description>&lt;blockquote&gt;
&lt;p&gt;今天说点儿与管理相关的事情&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;连续两年，我们部门都出现严重的运维事故，产品生成延迟时间较长。
去年是没有在第二天早上会商前提供，今年是连续两天某个模式卡住没有运行。&lt;/p&gt;
&lt;p&gt;虽然我一直认为运维事故可以在一定程度上通过某种技术手段避免，也一直在开展这方面的工作，例如今年早些时候撰写的几篇文章&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/02/2020-02-20-nwpc-system-notebook-check-cycle-complete/"&gt;NWPC业务系统笔记：检查单个时次是否运行完成&lt;/a&gt;》&lt;/li&gt;
&lt;li&gt;《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-04-ecflow-notebook-use-late-attribute/"&gt;ecFlow学习笔记：使用late设置超时报警&lt;/a&gt;》&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但领导认为这实际也是一个管理问题，并指出我们要从管理方面入手强化对业务系统的监控和保障。
并且第二次提到 NCEP &lt;strong&gt;用和我们一样的人力&lt;/strong&gt;就能很好地进行系统运维，而 NCEP 的产品是服务全世界的。&lt;/p&gt;
&lt;p&gt;前段时间刚好看了 NCEP Central Operations 的组织架构介绍，否则我还真和去年第一次听到类似对比的时候一样，认为这种差距完全是由我们个人造成的。&lt;/p&gt;
&lt;p&gt;下面我就根据 NCEP 官方网站的信息，介绍一下 NCO 各科的职责。
以下内容仅仅是对官网介绍的翻译，因为我毕竟没有额外的信息渠道。
不过从官网的介绍中完全能发现，运维上的差距并不只是由值班人员的责任心和运维科管理之类的因素造成的。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;NCO 的总体职责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运行 NCEP 业务模式系统
&lt;ul&gt;
&lt;li&gt;生成气候，天气，海洋，空间和环境风险等产品&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;管理对 NCEP 模式系统的改进
&lt;ul&gt;
&lt;li&gt;支持新模式或改进模式的研究，开发以及向业务的过渡&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;开发气象软件
&lt;ul&gt;
&lt;li&gt;由 NCEP 中心用于创建预报器生成的产品&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;管理数据和产品流
&lt;ul&gt;
&lt;li&gt;从 NCEP 中心，合作伙伴和客户获取数据，或向他们分发数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;笔者注：类似系统运行科的职责，但运行科不承担数据具体的分发，这项工作由信息中心提供。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="组织架构"&gt;组织架构&lt;/h2&gt;
&lt;p&gt;NCO 由 5 个科构成，如下图所示，原图来自 &lt;a href="https://www.nco.ncep.noaa.gov/director/orgchart.php"&gt;https://www.nco.ncep.noaa.gov/director/orgchart.php&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/ncep/nco-chart.png"&gt;
&lt;/figure&gt;

&lt;p&gt;分别是（中文名称是笔者翻译的，不是官方名称）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Network and Security Branch (NSB)：网络与安全科&lt;/li&gt;
&lt;li&gt;Operational Monitoring Branch (OMB)：业务监控科&lt;/li&gt;
&lt;li&gt;Software Development Branch (SDB)：软件开发科&lt;/li&gt;
&lt;li&gt;Infrastructure and Web Services Branch (IWSB)：基础设施与网络服务科&lt;/li&gt;
&lt;li&gt;Implementation and Data Services Branch (IDSB)：实施与数据服务科&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面介绍每个科的职责。&lt;/p&gt;</description></item><item><title>SQLAlchemy：执行简单的SQL语句</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-24-run-sql-statement-using-sqlalchemy/</link><pubDate>Sun, 24 May 2020 18:14:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-24-run-sql-statement-using-sqlalchemy/</guid><description>&lt;p&gt;虽然 SQLAlchemy 是 ORM 框架，但也可以用来执行 SQL 语句。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 SQLAlchemy 执行简单的 SQL 语句。&lt;/p&gt;
&lt;p&gt;示例代码来自正在开发的项目，从单位的台风数据库中检索数据，计划用于 CMA-PI 上的业务系统。&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;目标数据库支持 MySQL 客户端，所以需要使用 MySQL 的链接库。&lt;/p&gt;
&lt;p&gt;CMA-PI 上的 Python 环境没有安装 MySQL 库，所以笔者使用用户目录下的 Anaconda 环境，并使用 conda 安装 SQLAlchemy 和 pymysql。&lt;/p&gt;
&lt;h2 id="创建连接"&gt;创建连接&lt;/h2&gt;
&lt;p&gt;创建数据库连接&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sqlalchemy &lt;span style="color:#f92672"&gt;import&lt;/span&gt; create_engine
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;engine &lt;span style="color:#f92672"&gt;=&lt;/span&gt; create_engine(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;mysql+pymysql://&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;user&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;password&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;host&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;database_name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; engine&lt;span style="color:#f92672"&gt;.&lt;/span&gt;connect()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="执行查询"&gt;执行查询&lt;/h2&gt;
&lt;p&gt;构造带参数的查询 SQL 语句&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sqlalchemy.sql &lt;span style="color:#f92672"&gt;import&lt;/span&gt; text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; text(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;SELECT * &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;FROM &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;table_name&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;WHERE datetime=:start_time AND fcsthour=:forecast_hour&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;start_time&lt;/code&gt; 是起报时间，&lt;code&gt;forecast_hour&lt;/code&gt; 是预报时次。&lt;/p&gt;</description></item><item><title>NWPC笔记：预测动态步长模式积分时长 - 线性回归</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-23-nwpc-notebook-predict-step-time-for-meso-3km/</link><pubDate>Sat, 23 May 2020 21:37:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-23-nwpc-notebook-predict-step-time-for-meso-3km/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-22-nwpc-notebook-linear-regression-of-step-time-for-grapes-meso-3km/"&gt;NWPC笔记：分析动态步长模式积分时长 - 线性回归&lt;/a&gt;》中介绍如何使用线性回归拟合模式积分单步耗时，训练数据使用的是数据全集。&lt;/p&gt;
&lt;p&gt;但在实时业务中，我们往往需要尽可能早地判断模式积分是否异常，也就需要在模式积分过程中使用已完成的积分步骤时间来预测积分结束时间。&lt;/p&gt;
&lt;p&gt;本文介绍使用线性回归预测动态步长模式积分时长，对比使用不同的数据量作为训练集对最终预测结果的影响。
下面仅以 GRAPES MESO 3KM 模式系统为例进行说明。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-log-tool"&gt;nwpc-oper/nwpc-log-tool&lt;/a&gt; 工具获取积分单步耗时数据。&lt;/p&gt;
&lt;p&gt;载入需要使用的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_log_tool.forecast_output.grapes_meso_3km &lt;span style="color:#f92672"&gt;import&lt;/span&gt; get_step_time_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_log_tool.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建批量获取数据的函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_cum_time&lt;/span&gt;(start_time_list):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dict()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; start_time &lt;span style="color:#f92672"&gt;in&lt;/span&gt; start_time_list:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_meso_3km/log/fcst_ecf_out&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;start_time,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_step_time_from_file(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cumsum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;valid_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (df[&lt;span style="color:#e6db74"&gt;&amp;#34;valid_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data[start_time] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取 2020 年 4 月 10 日至 2020 年 4 月 30 日 00 时次的数据&lt;/p&gt;</description></item><item><title>NWPC笔记：分析动态步长模式积分时长 - 线性回归</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-22-nwpc-notebook-linear-regression-of-step-time-for-grapes-meso-3km/</link><pubDate>Fri, 22 May 2020 21:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-22-nwpc-notebook-linear-regression-of-step-time-for-grapes-meso-3km/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-compare-step-time-for-grapes-meso-3km/"&gt;NWPC笔记：对比模式积分时长 - 动态步长&lt;/a&gt;》中提到动态步长的模式积分单步耗时累计时间在正常情况和异常情况下也有不同的斜率。&lt;/p&gt;
&lt;p&gt;本文介绍使用线性回归拟合动态步长模式积分单步耗时，并对比两种情况下线性拟合的效果。
下面以 GRAPES MESO 3KM 为例进行说明。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;使用《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-compare-step-time-for-grapes-meso-3km/"&gt;NWPC笔记：对比模式积分时长 - 动态步长&lt;/a&gt;》中提到的 2020 年 4 月 13 日（异常情况）和 2020 年 4 月 22 日（正常情况）两个数据。
具体获取方法请查看该文章，不再详细介绍。&lt;/p&gt;
&lt;p&gt;下面首先以 2020 年 4 月 22 日的数据为例说明如何进行线性拟合。&lt;/p&gt;
&lt;p&gt;假设数据已被加载到 &lt;code&gt;df&lt;/code&gt; 中，对数据进行一定的处理。&lt;/p&gt;
&lt;p&gt;为了方便计算和显示，使用浮点类型的预报小时 &lt;code&gt;forecat_hour&lt;/code&gt; 作为自变量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_step_time_from_file(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df[&lt;span style="color:#e6db74"&gt;&amp;#34;step&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;valid_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (df[&lt;span style="color:#e6db74"&gt;&amp;#34;valid_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time)&lt;span style="color:#f92672"&gt;/&lt;/span&gt;pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df[&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cumsum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/linear-regress-3km/normal-df-table.png"&gt;
&lt;/figure&gt;

&lt;h2 id="使用-seaborn-绘制线性拟合曲线"&gt;使用 Seaborn 绘制线性拟合曲线&lt;/h2&gt;
&lt;p&gt;Seaborn 内置了线性拟合功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; seaborn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;whitegrid&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lmplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;df,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aspect&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/linear-regress-3km/normal-lmplot.png"&gt;
&lt;/figure&gt;

&lt;p&gt;可以看到，3小时以内的数据拟合有明显的误差。
这是因为3小时的那一步需要运行很长时间（100秒左右），导致前后的累计时间有明显的跃升。&lt;/p&gt;</description></item><item><title>关于技术报告的一些感想</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-20-technical-report-selection/</link><pubDate>Wed, 20 May 2020 21:08:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-20-technical-report-selection/</guid><description>&lt;p&gt;今天是单位2019年度优秀论文及技术报告评审结果公示的截止日期，我们通常认为下班相当于一天的结束。
所以，终于可以写点关于此次技术报告评选的感想了，免得被误认为对单位的评选有异议。&lt;/p&gt;
&lt;p&gt;很遗憾，我提交的技术报告《基于分布式调度的批量绘图技术研究》没有被评为优秀技术报告。
按照单位的政策，未被评选上的技术报告是不会被承认的，也就无法当成业绩。&lt;/p&gt;
&lt;p&gt;2019年末至今年初的半个月时间，我都在编写这篇技术报告，也是对 2017 年申请的青年基金课题的一个总结。
虽然我非常希望自己的报告能够获得单位的认可，但其实我也大概知道该报告没有评选上的部分原因。&lt;/p&gt;
&lt;p&gt;最大的问题是该报告没有实际应用的系统支持，仅是概念性质的介绍，并用了两个不太通用的示例。
单位评选的技术报告大多是与模式系统升级和模式研发相关的内容，往往都有业务化的支撑。
而我写的技术报告缺乏可以面向整个单位的应用示例，所以很难有足够的说服力。&lt;/p&gt;
&lt;p&gt;另一个关键的地方在于，该报告介绍的技术没有在 GRAPES 模式中得到应用。
仅浏览获奖技术报告的标题，就可以看到 15 篇报告的题目中有 14 篇有 GRAPES 关键字，都是围绕单位的核心任务来展开的研究。
而我写的技术报告没有明确指出 GRAPES 模式，毕竟绘图技术往往可以适用于任何模式系统。&lt;/p&gt;
&lt;p&gt;还有一点在于，这篇技术报告介绍的核心内容，即分布式调度技术，与气象局正在推广的气象大数据云平台中的加工流水线有所重叠。
虽然整套技术的思想不局限于特定的平台，其中的部分组件也可以用于加工流水线，但毕竟与主流发展方向略有差异，也没有在业务中实际应用，所以仅有一些借鉴意义。
2017 年我申请青年基金课题的时候，加工流水线还没有进入我们的视线，而 2020 年项目结题时，我的课题尚未应用，加工流水线已投入业务运行。
这就是效率和方向的问题。可能大家看到的趋势大体一致，但执行效率和实施的方法却有很大的差别。
尤其是在与气象信息化相关的领域，无论是支持力度还是其他方面，我们单位明显没有信息中心那样的优势。&lt;/p&gt;
&lt;p&gt;当然，最关键的还在于我自身，只要积极推进研究成果在业务系统中应用，还是有很大的机会的。
最近正在写 2019 年 GRAPES 专项课题的部分结题材料，深感自己平时工作缺乏系统性的总结。
一边工作一边总结，可能会有更好的效果。&lt;/p&gt;
&lt;p&gt;最后附上三位评审专家的评审意见，感谢各位专家。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;采用分布式调度技术，设计了绘图服务，对产品应用有比较好的支持作用。
建议提供测试结果，明确分布式调度的优势。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;对一种新的云计算技术应用到数值预报业务的方法实现，文字语言简练，对提高数值预报业务对接大数据云平台工作具有重要参考价值和指导意义
建议把技术报告封面排版调整，第一，二页合并&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;面向大数据和云技术在业务数值预报系统的应用，本文提出一种基于分布式调度的批量绘图技术，充分发挥分布式平台的优势，提高批量绘图任务的效率。该技术支持从不同数据来源获取数据，支持使用不同的工具进行数据处理和图形绘制，能满足气象领域多种应用场景下的批量绘图需求，具有广泛的应用前景。本文对技术细节、算法等方面描述细致清晰，科技含量高，文字语言简练，对提高数值预报研发和业务工作具有重要参考价值和指导意义。&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>使用Pyinstaller封装Python脚本</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-19-bundle-python-script-using-pyinstaller/</link><pubDate>Tue, 19 May 2020 21:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-19-bundle-python-script-using-pyinstaller/</guid><description>&lt;p&gt;NWPC 的业务系统中很少使用 Python 脚本，主要因为当前 HPC 上的 Python 环境安装和更新包不是很方便。&lt;/p&gt;
&lt;p&gt;我常用的方式是在 HPC 的用户目录下自己安装一个 Python 环境，并使用代理在线安装软件包。
具体方法参见《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-04-22-user-level-python-for-hpc/"&gt;HPC用户安装Python解决方案&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;但如果想在业务系统中使用安装在用户目录的 Python 环境，会有很多问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务系统不应该依赖非业务账户的文件&lt;/li&gt;
&lt;li&gt;业务账户不应该单独安装 Python 环境，可能会影响其他业务的正常运行&lt;/li&gt;
&lt;li&gt;业务账户不应该使用代理连接互联网&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除了以上几点外，我在测试时候发现另一个问题，也是用户账户下 Python 环境的最大问题：&lt;strong&gt;import加载速度太慢&lt;/strong&gt;。
以笔者多个平台的使用经验来看，这个问题似乎是 CMA-PI 上独有的。&lt;/p&gt;
&lt;p&gt;下面以最近正做的用于预测积分时间的 ecFlow 系统为例说明这个现象，并介绍如何通过 Pyinstaller 封装脚本实现快速加载。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;在之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-11-nwpc-notebook-predict-using-linear-regression-for-step-time/"&gt;NWPC笔记：预测模式积分时长 - 线性回归&lt;/a&gt;》基础上，构建 ecFlow 系统，实时读取模式积分输出，并计算积分总体耗时。&lt;/p&gt;
&lt;p&gt;系统使用 &lt;a href="https://github.com/nwpc-oper/nwpc-log-tool"&gt;nwpc-oper/nwpc-log-tool&lt;/a&gt; 获取积分耗时信息，并使用 scikit-learn 提供的线性回归方法预测总体耗时。&lt;/p&gt;
&lt;p&gt;本文仅关注 Python 脚本 import 载入速度的问题。&lt;/p&gt;
&lt;h2 id="现状"&gt;现状&lt;/h2&gt;
&lt;p&gt;使用笔者个人账户下安装的 Python 环境，执行 Python 脚本，输出如下信息（有省略）：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;run script...Tue May 19 04:43:54 GMT 2020
begin...2020-05-19 04:45:32.081343
...skip..
finish...2020-05-19 04:45:38.785521
finish script...Tue May 19 04:45:56 GMT 2020
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;第一行和最后一行时间是 Shell 执行 Python 脚本前后，调用 &lt;code&gt;date&lt;/code&gt; 命令的输出。&lt;/p&gt;</description></item><item><title>NWPC笔记：对比模式积分时长 - 动态步长</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-compare-step-time-for-grapes-meso-3km/</link><pubDate>Sun, 17 May 2020 16:52:59 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-compare-step-time-for-grapes-meso-3km/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-get-step-time-for-grapes-meso-3km/"&gt;NWPC笔记：获取模式积分时长 - 动态步长&lt;/a&gt;》介绍如何获取动态步长的模式积分时长，并使用积分时间在正常范围内的时次（2020042200）作为示例。&lt;/p&gt;
&lt;p&gt;本文进一步对比积分时间正常和异常的情况下积分时间的变化，同样只针对 GRAPES MESO 3KM 系统。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;获取 2020 年 4 月 13 日 00 时次的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-04-13 00:00:00&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_meso_3km/log/fcst_ecf_out&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;start_time,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_step_time_from_file(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf[&lt;span style="color:#e6db74"&gt;&amp;#34;step&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; edf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; edf[&lt;span style="color:#e6db74"&gt;&amp;#34;valid_time&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start_time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf[&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; edf[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cumsum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/compare-meso-3km/edf-table.png"&gt;
&lt;/figure&gt;

&lt;h2 id="绘制统计图形"&gt;绘制统计图形&lt;/h2&gt;
&lt;p&gt;使用 Seaborn 绘制统计图形&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; seaborn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;whitegrid&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="折线图"&gt;折线图&lt;/h3&gt;
&lt;p&gt;从第 2 步骤开始绘制折线图&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fig, ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;subplots(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lineplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;step&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;edf[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ax
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/compare-meso-3km/edf-line.png"&gt;
&lt;/figure&gt;

&lt;h3 id="直方图"&gt;直方图&lt;/h3&gt;
&lt;p&gt;从第 2 步骤开始绘制直方图&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fig, ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;subplots(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;distplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; edf[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;][&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ax
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/get-meso-3km/df-distplot.png"&gt;
&lt;/figure&gt;

&lt;p&gt;以上两个图基本与积分正常时次的图形一致，看不出积分时间异常的原因。&lt;/p&gt;</description></item><item><title>NWPC笔记：获取模式积分时长 - 动态步长</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-get-step-time-for-grapes-meso-3km/</link><pubDate>Sun, 17 May 2020 11:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-17-nwpc-notebook-get-step-time-for-grapes-meso-3km/</guid><description>&lt;p&gt;在《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-06-nwpc-notebook-get-step-time-for-grapes-gfs/"&gt;NWPC笔记：获取模式积分时长 - 恒定步长&lt;/a&gt;》中，笔者介绍如何从恒定步长模式的输出日志获取每步积分的时长。&lt;/p&gt;
&lt;p&gt;NWPC 业务系统中有另一类模式系统，采用自动调制时间步长方案，每步积分对应的步长会动态调整，随之而来的就是积分预报固定时间对应的积分步数不一致。&lt;/p&gt;
&lt;p&gt;本文介绍如何获取动态步长的模式积分时长，以下只针对 GRAPES MESO 3KM 系统。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="模式积分输出"&gt;模式积分输出&lt;/h2&gt;
&lt;p&gt;模式积分的输出保存到模式积分作业标准输出重定向的文件中，即积分作业 &lt;code&gt;fcst.job1&lt;/code&gt; 的标准输出 &lt;code&gt;fcst.1&lt;/code&gt; 文件中。&lt;/p&gt;
&lt;p&gt;积分步长不变时，模式输出如下所示。与上一篇文章介绍的 GRAPES GFS 相比，输出增加括号中的时间，表示该步骤对应的预报时刻。
可以看到，默认情况下，积分步长是 30 秒。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; begin of gcr 1.027551119140290E-005
 RES of gcr 9.348691670014106E-013 in 31 iterations 
Timing for processing for step 41 (2020051600:20:00): 1.16430 elapsed seconds.
Timing for processing for step 41 (2020051600:20:00): 1.16364 cpu seconds.
 begin of gcr 1.033965735220742E-005
 RES of gcr 9.367767677783578E-013 in 31 iterations 
Timing for processing for step 42 (2020051600:20:30): 1.15810 elapsed seconds.
Timing for processing for step 42 (2020051600:20:30): 1.15735 cpu seconds.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;积分步长有变化时，模式输出如下所示。每步对应的预报时刻会有相应的变化。&lt;/p&gt;</description></item><item><title>Matplotlib中使用Latex格式化文本</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-16-format-text-using-latex-in-matplotlib/</link><pubDate>Sat, 16 May 2020 20:16:46 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-16-format-text-using-latex-in-matplotlib/</guid><description>&lt;p&gt;最近同事在研究使用 Matplotlib 如何绘制类似下面的统计图形，主要借鉴其中的标注。
难点在于标题由不同大小的多行文字构成。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/visual/ecmwf-total-preciptiation-brier-skill-score-example.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;来自 ECMWF 网站的示例图片&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;笔者推测上面的图形使用 ECMWF 自己开发的绘图库 &lt;a href="https://confluence.ecmwf.int/display/MAGP/Magics"&gt;Magics&lt;/a&gt; 绘制。&lt;/p&gt;
&lt;h2 id="magics-文本"&gt;Magics 文本&lt;/h2&gt;
&lt;p&gt;Magics 中的文本显示支持基本的 HTML 标签。&lt;/p&gt;
&lt;p&gt;例如在 &lt;a href="https://confluence.ecmwf.int/display/MAGP/Text+plotting+tutorial"&gt;Text plotting tutorial&lt;/a&gt; 中的示例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;title &lt;span style="color:#f92672"&gt;=&lt;/span&gt; magics&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mtext(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Positive values are &amp;lt;font colour=&amp;#39;red&amp;#39; size=&amp;#39;1&amp;#39;&amp;gt;red &amp;lt;/font&amp;gt; ☂&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Negative values are &amp;lt;font colour=&amp;#39;blue&amp;#39; size=&amp;#39;1&amp;#39;&amp;gt;blue &amp;lt;/font&amp;gt; ☔&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;As you see, you can use HTML symbols too, like °C, Ω, μ, ☈, ☀&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_justification &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_font_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.7&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_colour &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;charcoal&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;snowman &lt;span style="color:#f92672"&gt;=&lt;/span&gt; magics&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mtext(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;☃&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_mode &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;positional&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_box_x_position &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12.&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_box_y_position &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;12.&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_box_x_length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_box_y_length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_justification &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;left&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_font_size &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5.7&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text_colour &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;white&amp;#34;&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;magics&lt;span style="color:#f92672"&gt;.&lt;/span&gt;plot(projection, ta, cont_anomaly, coast, legend, title,snowman)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/visual/ecmwf-magics-text-plotting-tutorial-example.png"&gt;
&lt;/figure&gt;

&lt;p&gt;但遗憾的是，Matplotlib 似乎不支持 HTML 标签。
不过有替代方案。&lt;/p&gt;</description></item><item><title>变更ecFlow服务运行节点</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-15-ecflow-notebook-change-server-host/</link><pubDate>Fri, 15 May 2020 21:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-15-ecflow-notebook-change-server-host/</guid><description>&lt;p&gt;昨天 CMA-PI 的重启似乎没有带来好的兆头，今天早上 NWPC 业务系统使用的两个节点 login_b01 和 login_b02 几乎同一时间无法使用，导致调度业务系统的 ecFlow 服务完全停止。&lt;/p&gt;
&lt;p&gt;为了不影响今天 00 时次的产品分发，我们决定尝试切换 ecFlow 的运行节点。&lt;/p&gt;
&lt;h2 id="基础"&gt;基础&lt;/h2&gt;
&lt;p&gt;ecFlow 服务会定时将当前的状态保存到 checkpoint 文件中，文件位置由 &lt;code&gt;ECF_CHECK&lt;/code&gt; 和 &lt;code&gt;ECF_CHECKOLD&lt;/code&gt; 指定。
其中 &lt;code&gt;ECF_CHECK&lt;/code&gt; 是最新的备份文件，而 &lt;code&gt;ECF_CHECKOLD&lt;/code&gt; 是上一次的备份文件。
这种&lt;strong&gt;双备份&lt;/strong&gt;机制正是今天恢复系统的关键。&lt;/p&gt;
&lt;p&gt;另外，CMA-PI 上使用的是共享文件系统，某个节点 ecFlow 生成的文件可以被其它所有节点访问到。
ecFlow 服务运行的节点自身除了少量在该节点运行的串行作业外，不保存任何与业务系统相关的信息，这也是能便捷切换节点的关键因素。&lt;/p&gt;
&lt;h2 id="方法"&gt;方法&lt;/h2&gt;
&lt;p&gt;假设我们需要将 login_b01 上运行使用 31066 端口的 ecFlow 切换到 login_b09 上。&lt;/p&gt;
&lt;p&gt;login_b01 的 ecFlow 服务的 checkpoint 文件名为：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;login_b01.31066.check&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;需要将其改为&lt;/p&gt;
&lt;p&gt;&lt;code&gt;login_b09.31066.check&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后将文本文件中所有的 &lt;code&gt;login_b01&lt;/code&gt; 替换为 &lt;code&gt;login_b09&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;因为节点名称具有特殊性，所以我们在设计业务系统时不会使用类似的名字。
节点名称会出现在如下的变量定义中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ECF_NODE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECF_HOST&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECF_LOG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECF_CHECK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECF_CHECKOLD&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;修改后，使用相同的端口在 login_b09 节点上启动新的 ecFlow 即可加载 login_b01 节点上 ecFlow 的所有状态信息。&lt;/p&gt;</description></item><item><title>视界：ECMWF产品发布系统的新功能</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-14-view-new-capabilities-ecmwfs-product-dissemination-system/</link><pubDate>Thu, 14 May 2020 20:18:36 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-14-view-new-capabilities-ecmwfs-product-dissemination-system/</guid><description>&lt;blockquote&gt;
&lt;p&gt;最近部门在推动将产品后处理系统从高性能计算机迁移到气象大数据云平台，ECMWF 的这篇文章很有参考价值&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 163 - Spring 2020 中 Matthias Zink 和 Meghan Plumridge 的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/163/computing/new-capabilities-ecmwfs-product-dissemination-system"&gt;The new capabilities of ECMWF’s product dissemination system&lt;/a&gt;》，版权归原作者所有。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;ECMWF 的产品分发系统每天向 ECMWF 的不同用户提供大约 240,000 个后处理文件。
分发系统的两个重要部分是“产品需求编辑器（Product Requirements Editor）”，在其中用户生成数据请求；以及“产品生成系统（Product Generation System）”，在该系统中根据这些请求定制数据。
几年前，对产品分发系统进行了一次重大审查，确定了这两个方面需要改进的关键领域，以便将来更好地为我们的会员国，合作国和其他用户提供服务。
解决这些关键问题已导致计算效率的显着提高，更可靠和强大的服务以及包括新功能在内的用户界面的改进。
它还为将产品分发系统迁移到博洛尼亚的新数据中心奠定了基础。
产品发布系统的第三个组件 ECMWF 产品数据存储（ECPDS）的改进已在较早之前实施，并在之前的 Newsletter 文章（Gougeon，2019）中进行了描述。
新产品发布系统已经实施，并得到了 ECMWF 众多员工的支持，包括用户支持，开发，产品和计算专家。&lt;/p&gt;
&lt;h3 id="动机"&gt;动机&lt;/h3&gt;
&lt;p&gt;促使审查的一个重要问题是可伸缩性，尤其是在查看近年来生成和分发的数据量的增长时。
图 1a 显示了过去 13 年中分发量的增长。
某些较大的增长可归因于模型分辨率的升级，例如 2013 年和 2016 年。
然而，其他一些增长只是由会员国，成员国和其他用户对数据需求的增长所驱动。
这种增长的一个原因是由于 2018 年向商业用户提供了高频产品。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;High-frequency products&lt;/strong&gt;
ECMWF 的高频产品是逐小时天气预报产品，每天四次（06 UTC，12 UTC，18 UTC 00 UTC）生成前 90 小时产品。
而核心产品每天在 00 和 12 UTC 生成，每 3 小时和每 6 小时生成高分辨率预报（HRES）10天数据和集合预报（ENS）15天数据。
高频数据来自于 1991 年成立的 ECMWF 的边界条件可选计划。
该计划的主要目的是向 ECMWF 的成员国和合作国提供此类数据，以用作其有限区域模型的边界条件。
自 2018 年 10 月以来，该计划的数据已应要求提供给所有实时数据许可证持有者。&lt;/p&gt;</description></item><item><title>ecFlow笔记：定时任务没有启动 - 分析</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-13-ecflow-notebook-why-timed-task-not-run/</link><pubDate>Wed, 13 May 2020 23:28:29 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-13-ecflow-notebook-why-timed-task-not-run/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-12-ecflow-notebook-timed-task-not-run/"&gt;ecFlow笔记：定时任务没有启动 - 排查&lt;/a&gt;》中推测定时任务没有启动的原因是因为作业生成超时，并提到该推测成立需要下面两个必要条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ecFlow 中作业生成和检查依赖关系等操作是串行的&lt;/li&gt;
&lt;li&gt;ecFlow 检查时间依赖不是 &amp;gt;=，即超过时间点的任务不会被启动&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文逐条分析以上两个条件，为上一篇文章的推测提供依据。&lt;/p&gt;
&lt;h2 id="串行处理"&gt;串行处理&lt;/h2&gt;
&lt;p&gt;ecFlow 服务端使用 &lt;code&gt;Boost::Asio&lt;/code&gt; 实现事件响应，而 &lt;code&gt;Boost::Asio&lt;/code&gt; 即支持单线程也支持多线程。&lt;/p&gt;
&lt;p&gt;源码中使用 &lt;code&gt;ECFLOW_MT&lt;/code&gt; 宏定义是否使用多线程模式，在 Server\src\Server.hpp 中有下面的代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ECFLOW_MT See doc/multi-threaded-server.tar/ddoc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//#define ECFLOW_MT 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifdef ECFLOW_MT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34;CConnection.hpp&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// Must come before boost/serialisation headers.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34;Connection.hpp&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt; &lt;/span&gt;&lt;span style="color:#75715e"&gt;// Must come before boost/serialisation headers.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34;ClientToServerRequest.hpp&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34;ServerToClientResponse.hpp&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;说明默认情况下，&lt;code&gt;ECFLOW_MT&lt;/code&gt; 未定义，使用单线程模式。&lt;/p&gt;
&lt;p&gt;在 Server\src\ServerOptions.cpp 中可以看到，如果定义了 &lt;code&gt;ECFLOW_MT&lt;/code&gt;，&lt;code&gt;ecflow_server&lt;/code&gt; 命令会有 &lt;code&gt;threads&lt;/code&gt; 参数。&lt;/p&gt;
&lt;p&gt;在 CMA-PI 上运行 &lt;code&gt;ecflow_server -h&lt;/code&gt;，列出的参数中没有 &lt;code&gt;threads&lt;/code&gt;，说明我们使用的 ecFlow 是单线程模式。&lt;/p&gt;
&lt;p&gt;在 Server\src\NodeTreeTraverser.cpp 中有下面的函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; NodeTreeTraverser&lt;span style="color:#f92672"&gt;::&lt;/span&gt;start_timer()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/// Appears that expires_from_now is more accurate then expires_at i.e timer_.expires_at( timer_.expires_at() + boost::posix_time::seconds( poll_at ) );
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	timer_.expires_from_now( boost&lt;span style="color:#f92672"&gt;::&lt;/span&gt;posix_time&lt;span style="color:#f92672"&gt;::&lt;/span&gt;seconds( &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; ) );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#ifdef ECFLOW_MT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	timer_.async_wait( server_&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;strand_.wrap( boost&lt;span style="color:#f92672"&gt;::&lt;/span&gt;bind( &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;NodeTreeTraverser&lt;span style="color:#f92672"&gt;::&lt;/span&gt;traverse,&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;,boost&lt;span style="color:#f92672"&gt;::&lt;/span&gt;asio&lt;span style="color:#f92672"&gt;::&lt;/span&gt;placeholders&lt;span style="color:#f92672"&gt;::&lt;/span&gt;error ) ) );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	timer_.async_wait( server_&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;io_service_.wrap( boost&lt;span style="color:#f92672"&gt;::&lt;/span&gt;bind( &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;NodeTreeTraverser&lt;span style="color:#f92672"&gt;::&lt;/span&gt;traverse,&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;,boost&lt;span style="color:#f92672"&gt;::&lt;/span&gt;asio&lt;span style="color:#f92672"&gt;::&lt;/span&gt;placeholders&lt;span style="color:#f92672"&gt;::&lt;/span&gt;error ) ) );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在单线程模式中，使用 &lt;code&gt;io_service_&lt;/code&gt; 执行 &lt;code&gt;NodeTreeTraverser::traverse&lt;/code&gt; 函数。&lt;code&gt;io_service_&lt;/code&gt; 是 &lt;code&gt;boost::asio::io_service&lt;/code&gt; 对象，同时只能运行一个函数，也就是 &lt;code&gt;NodeTreeTraverser::traverse&lt;/code&gt; 函数是串行执行的。&lt;/p&gt;</description></item><item><title>ecFlow笔记：定时任务没有启动 - 排查</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-12-ecflow-notebook-timed-task-not-run/</link><pubDate>Tue, 12 May 2020 22:08:35 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-12-ecflow-notebook-timed-task-not-run/</guid><description>&lt;p&gt;最近几天接连发生业务系统没有按时运行的故障，给我们维护人员带来巨大的压力。&lt;/p&gt;
&lt;p&gt;先不提之前的故障是什么原因，也不管我们应该如何避免这类故障，下面只涉及今天早上应该启动而没启动的任务。&lt;/p&gt;
&lt;h2 id="故障"&gt;故障&lt;/h2&gt;
&lt;p&gt;obs_rafs 系统每个时次对应的任务有两个启动时间点，21 时次对应 22:30 和 23:10。&lt;/p&gt;
&lt;p&gt;下图是今天早上的截图，昨天 21 时次中 23:10 的任务正常启动，但 22:30 的任务尚未运行。注：00时次是手动启动的，不是异常情况。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/not-run/nwpc-qu-obs-rafs-21.jpg"&gt;
&lt;/figure&gt;

&lt;p&gt;单从这一情况无法直接判断原因，可能有多种情况。&lt;/p&gt;
&lt;p&gt;不过，一个多小时后我们再次发现 grapes_meso_3km_v4_4 系统的 18 时次也没有启动，依赖时间是 22:31，与 obs_rafs 的 21 时次中一个启动时间仅差 1 分钟。如下图所示&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/not-run/nwpc-qu-meso-3km.png"&gt;
&lt;/figure&gt;

&lt;p&gt;这就说明了 22:30 的时候，ecFlow 一定有某种故障。&lt;/p&gt;
&lt;h2 id="排查"&gt;排查&lt;/h2&gt;
&lt;p&gt;检查 ecFlow 的日志，从中提取出所有 5 月 11 日的条目，并查找 22:30 左右的记录，发现下面的日志信息：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MSG:[22:27:25 11.5.2020] chd:complete /mosaic_v3/21/archiving
LOG:[22:27:25 11.5.2020] complete: /mosaic_v3/21/archiving
LOG:[22:27:25 11.5.2020] complete: /mosaic_v3/21
LOG:[22:27:25 11.5.2020] queued: /mosaic_v3
LOG:[22:33:08 11.5.2020] submitted: /mosaic_v3/housekeeping job_size:2917
LOG:[22:33:08 11.5.2020] submitted: /mosaic_v3
WAR:[22:33:08 11.5.2020] Job generation for task /mosaic_v3/housekeeping took 342950ms, Exceeds ECF_TASK_THRESHOLD(4000ms)
ERR:[22:33:08 11.5.2020] Jobs::generate: job generation time(342 seconds) is greater than job submission interval of 60 seconds!!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 22:27:25 时，&lt;code&gt;/mosaic_v3/21/archiving&lt;/code&gt; 任务完成，后续应该立即提交 &lt;code&gt;/mosaic_v3/housekeeping&lt;/code&gt; 任务。
但 &lt;code&gt;/mosaic_v3/housekeeping&lt;/code&gt; 任务的作业脚本生成环节超时，耗时 342 秒，将近 6 分钟，直到 22:33:08 才完成。&lt;/p&gt;</description></item><item><title>NWPC笔记：预测模式积分时长 - 线性回归</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-11-nwpc-notebook-predict-using-linear-regression-for-step-time/</link><pubDate>Mon, 11 May 2020 20:21:35 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-11-nwpc-notebook-predict-using-linear-regression-for-step-time/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-10-nwpc-notebook-linear-regression-of-step-time-for-grapes-gfs/"&gt;NWPC笔记：分析模式积分时长 - 线性回归&lt;/a&gt;》中介绍如何使用线性回归拟合模式积分单步耗时，训练数据使用的是数据全集。&lt;/p&gt;
&lt;p&gt;但在实时业务中，我们往往需要尽可能早地判断模式积分是否异常，也就需要在模式积分过程中使用已完成的积分步骤时间来预测积分结束时间。&lt;/p&gt;
&lt;p&gt;本文介绍使用线性回归预测模式积分时长，对比使用不同的数据量作为训练集对最终预测结果的影响。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;和上一篇文章一样，使用 &lt;a href="https://github.com/nwpc-oper/nwpc-log-tool"&gt;nwpc-oper/nwpc-log-tool&lt;/a&gt; 获取单步积分数据。&lt;/p&gt;
&lt;p&gt;创建函数，批量获取运行时间。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_cum_time&lt;/span&gt;(start_time_list):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dict()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; start_time &lt;span style="color:#f92672"&gt;in&lt;/span&gt; start_time_list:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/log/fcst_long_std_out&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;start_time,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_step_time_from_file(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cumsum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data[start_time] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df[&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; df
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取 2020 年 4 月 10 日至 2020 年 4 月 30 日的数据，并输出积分总时间（单位：秒）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_cum_time(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date_range(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2020-04-10&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2020-04-30&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; freq&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;D&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;iloc[&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;2020-04-10 23.170123
2020-04-11 23.935507
2020-04-12 22.960625
2020-04-13 44.652387
2020-04-14 23.098123
2020-04-15 22.748205
2020-04-16 22.902938
2020-04-17 23.128332
2020-04-18 23.376948
2020-04-19 23.527448
2020-04-20 22.829743
2020-04-21 32.210792
2020-04-22 29.892152
2020-04-23 23.042733
2020-04-24 22.938663
2020-04-25 22.867722
2020-04-26 22.937087
2020-04-27 31.016060
2020-04-28 32.708422
2020-04-29 31.268345
2020-04-30 22.859272
Name: 2880, dtype: float64
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从下面的图形可以看到有几天的积分耗时明显异常。&lt;/p&gt;</description></item><item><title>NWPC笔记：分析模式积分时长 - 线性回归</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-10-nwpc-notebook-linear-regression-of-step-time-for-grapes-gfs/</link><pubDate>Sun, 10 May 2020 16:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-10-nwpc-notebook-linear-regression-of-step-time-for-grapes-gfs/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-09-nwpc-notebook-compare-step-time-for-grapes-gfs/"&gt;NWPC笔记：对比模式积分时长 - 恒定步长&lt;/a&gt;》中提到模式积分单步耗时累计时间在正常情况和异常情况下有不同的斜率。&lt;/p&gt;
&lt;p&gt;本文介绍使用线性回归拟合模式积分单步耗时，并对比两种情况下线性拟合的效果。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;使用《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-09-nwpc-notebook-compare-step-time-for-grapes-gfs/"&gt;NWPC笔记：对比模式积分时长 - 恒定步长&lt;/a&gt;》中提到的 2020 年 4 月 13 日（异常情况）和 2020 年 5 月 5 日（正常情况）两个数据。
具体获取方法请查看该文章，不再详细介绍。&lt;/p&gt;
&lt;p&gt;下面首先以 2020 年 5 月 5 日的数据为例说明如何进行线性拟合。&lt;/p&gt;
&lt;p&gt;假设数据已被加载到 &lt;code&gt;df&lt;/code&gt; 中。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/linear-regression/normal-df-table.png"&gt;
&lt;/figure&gt;

&lt;h2 id="使用-seaborn-绘制线性拟合曲线"&gt;使用 Seaborn 绘制线性拟合曲线&lt;/h2&gt;
&lt;p&gt;Seaborn 内置了线性拟合功能。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; seaborn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;whitegrid&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lmplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;step&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;df,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; aspect&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/linear-regression/normal-lmplot.png"&gt;
&lt;/figure&gt;

&lt;p&gt;点数量太多，导致拟合直线和数据点混在一块，也说明了正常情况下的数据有很好的线性关系。&lt;/p&gt;
&lt;h2 id="使用-scikit-learn-计算线性回归"&gt;使用 scikit-learn 计算线性回归&lt;/h2&gt;
&lt;p&gt;使用 scikit-learn 提供的线性回归算法 LinearRegression 计算线性拟合。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sklearn &lt;span style="color:#f92672"&gt;import&lt;/span&gt; linear_model
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将积分步数处理成 scikit-learn 需要的二维变量。&lt;/p&gt;</description></item><item><title>NWPC笔记：对比模式积分时长 - 恒定步长</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-09-nwpc-notebook-compare-step-time-for-grapes-gfs/</link><pubDate>Sat, 09 May 2020 21:48:30 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-09-nwpc-notebook-compare-step-time-for-grapes-gfs/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-06-nwpc-notebook-get-step-time-for-grapes-gfs/"&gt;NWPC笔记：获取模式积分时长 - 恒定步长&lt;/a&gt;》介绍如何从模式输出日志获取模式积分每步的时长，并绘制一些统计图形。选用的是模式积分耗时处于正常范围内的时次。
但从文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-25-analytic-nwp-model-running-time/"&gt;统计数值天气预报模式积分运行时间&lt;/a&gt;》中可以看到，个别情况下模式积分时长会显著增加。&lt;/p&gt;
&lt;p&gt;本文使用《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-06-nwpc-notebook-get-step-time-for-grapes-gfs/"&gt;NWPC笔记：获取模式积分时长 - 恒定步长&lt;/a&gt;》中的方法，对比 GRAPES GFS 模式积分耗时正常和异常情况下每步积分的时长变化。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;以下假设已按照前一篇文章中的方法，将积分时间正常的 2020050500 时次的数据保存到 &lt;code&gt;df&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;加载积分时间超时的 2020041300 时次的数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/log/fcst_long_std_out&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2020041300&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_step_time_from_file(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf[&lt;span style="color:#e6db74"&gt;&amp;#34;step&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; edf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;index
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf[&lt;span style="color:#e6db74"&gt;&amp;#34;ctime&amp;#34;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; edf[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cumsum()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;edf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/compare-gfs/edf-table.png"&gt;
&lt;/figure&gt;

&lt;h2 id="绘制统计图形"&gt;绘制统计图形&lt;/h2&gt;
&lt;p&gt;与前一篇文章一样，使用 Seaborn 绘制统计图形&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; seaborn &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; sns
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;whitegrid&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="折线图"&gt;折线图&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fig, ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;subplots(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sns&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lineplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;step&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;edf[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ax&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ax
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/nwpc/step-time/compare-gfs/edf-line.png"&gt;
&lt;/figure&gt;

&lt;p&gt;可以看到，4 月 13 日 00 时次的积分单步耗时明显比 5 月 5 日 00 时次多，甚至出现单步耗时 17 秒的情况。&lt;/p&gt;</description></item><item><title>NWPC笔记：获取模式积分时长 - 恒定步长</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-06-nwpc-notebook-get-step-time-for-grapes-gfs/</link><pubDate>Wed, 06 May 2020 22:07:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-06-nwpc-notebook-get-step-time-for-grapes-gfs/</guid><description>&lt;p&gt;在《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-25-analytic-nwp-model-running-time/"&gt;统计数值天气预报模式积分运行时间&lt;/a&gt;》中，笔者介绍使用 ecFlow 日志统计模式积分运行时间的统计结果，仅能展示模式积分的总体时长和时间段，缺乏积分步的细节信息。&lt;/p&gt;
&lt;p&gt;随后笔者在《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-27-analytic-nwp-model-production-time/"&gt;统计数值天气预报模式产品生成时间&lt;/a&gt;》中介绍使用 NWPC 消息平台统计产品生成的时间，可以略微展现模式积分的部分细节。&lt;/p&gt;
&lt;p&gt;但在《&lt;a href="https://blog.perillaroc.wang/post/2020/05/2020-05-01-analytic-nwp-production-file-created-time-multi-bootstrap/"&gt;统计数值预报产品生成时间：重采样&lt;/a&gt;》中可以看到，产品生成时间并不是随着产品时效单调递增的，所以想要获取模式积分的细节信息，还得从模式积分本身入手。&lt;/p&gt;
&lt;p&gt;本文介绍如何从模式积分输出中获取模式积分时长，只考虑模式步长恒定的 GRAPES GFS 系统。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="模式积分输出"&gt;模式积分输出&lt;/h2&gt;
&lt;p&gt;在模式积分输出的 &lt;code&gt;std.out.0000&lt;/code&gt; 文件中，有每个积分步骤的耗时。例如&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Timing for processing for step 1: 15.51460 elapsed seconds.
 begin of gcr 6.001155404370011E-005
 RES of gcr 1.006302069134485E-023 in 37 iterations 
Timing for processing for step 2: 0.30060 elapsed seconds.
 begin of gcr 5.512293401798762E-005
 RES of gcr 1.112349462442307E-023 in 37 iterations 
Timing for processing for step 3: 0.34650 elapsed seconds.
 begin of gcr 5.254961640146931E-005
 RES of gcr 8.206002160154577E-024 in 37 iterations 
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;积分步数和每步耗时有明显的标志，可以使用正则表达式提取。&lt;/p&gt;</description></item><item><title>五一劳动节快乐</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-04-international-workers-day/</link><pubDate>Mon, 04 May 2020 17:58:02 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-04-international-workers-day/</guid><description>&lt;blockquote&gt;
&lt;p&gt;劳动人民最光荣&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天是五四青年节，五一小长假即将完结。
最近一段时间接连吃到几个大瓜，作为吃瓜群众的一员，也该写一些纪念一下特殊时期的劳动节。&lt;/p&gt;
&lt;p&gt;近期一系列大瓜中，还是“阅文集团新合同”最能引起我的共鸣。&lt;/p&gt;
&lt;p&gt;虽然我不是网络写手，也没从文字中获过利（主要是文笔太差），但我从刚开始接触互联网就一直坚持写博客，已写了 13 年。&lt;/p&gt;
&lt;h2 id="百度空间"&gt;百度空间&lt;/h2&gt;
&lt;p&gt;我曾经是 &lt;strong&gt;百度空间&lt;/strong&gt; 的铁杆用户。虽然百度空间经历一系列改版，最终将自己玩没了，但我依然很怀念当年写空间刷数据的日子。
从 2007 年初大一上学期末在学校图书馆写的第一篇文章开始，我就始终将百度空间作为自己的博客，直到 2011 年底，发现百度空间协议中令我无法接受的条款。&lt;/p&gt;
&lt;p&gt;下面摘抄自 2011 年 12 月 19 日写的博客《关于百度空间的使用协议》。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;3.6 公共区域内容的许可
用户同意将您在本服务公共区域（公共区域指一般公众用户可以使用的区域）内上传之照片、文字授予百度全球性、免许可费、非独家、可完全转授权、及永久有效的使用权利，百度可以为了展示、散布及推广张贴前述内容之特定目的，将前述内容以使用、复制、修改、改编、出版、翻译、据以创作衍生作品后用于互联网增值业务或电信增值业务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就意味着在百度空间发布的文章，将可以被百度无限制使用，并任意授权给第三方。
相当于使用 &lt;a href="https://creativecommons.org/share-your-work/public-domain/cc0/"&gt;CC0&lt;/a&gt; 协议。&lt;/p&gt;
&lt;p&gt;同样，这篇博文中也记录了当时《新浪网络服务使用协议》的内容&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于用户通过新浪网络服务（包括但不限于论坛、BBS、新闻评论、个人家园）上传到新浪网站上可公开获取区域的任何内容，用户同意新浪在全世界范围内具有免费的、永久性的、不可撤销的、非独家的和完全再许可的权利和许可，以使用、复制、修改、改编、出版、翻译、据以创作衍生作品、传播、表演和展示此等内容（整体或部分），和/或将此等内容编入当前已知的或以后开发的其他任何形式的作品、媒体或技术中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;百度空间已不复存在，但最新版的《&lt;a href="https://passport.sinaimg.cn/html/sso/signupagreement.html"&gt;新浪网络服务使用协议&lt;/a&gt;》还是可以查到，相关内容如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于您通过新浪网络服务上传到新浪网站上可公开获取区域的任何内容，您同意新浪及其关联公司在全世界范围内具有免费的、永久性的、不可撤销的、非独家的和完全再许可的权利和许可，以使用、复制、修改、改编、出版、翻译、据以创作衍生作品、传播、表演和展示此等内容（整体或部分），和/或将此等内容编入当前已知的或以后开发的其他任何形式的作品、媒体或技术中，您同意新浪有权就任何主体侵权而单独提起诉讼。您对新浪及其关联公司的前述授权并不改变您对发布内容的所有权及知识产权归属，也并不影响您行使对发布内容的合法权利。新浪将尽最大的商业努力合理使用您的授权内容，但并不代表新浪及其关联公司承诺一定会使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;相较于 9 年前，添加“并不改变您对发布内容的所有权及知识产权归属”这段话，虽然我觉得没有太大意义。
另外还增加了没有明确定义的“&lt;strong&gt;关联公司&lt;/strong&gt;”，整个服务协议中只有该条目出现 &lt;strong&gt;关联公司&lt;/strong&gt; 字样，值得深思。&lt;/p&gt;
&lt;p&gt;回到 2011 年，当时发现这样无法接受的条款后，我果断放弃继续在百度空间上撰写博文。
所以，从 2012 年开始，在新浪 SAE 上搭建 WordPress 博客，并在百度空间改版后，完全弃用百度空间。&lt;/p&gt;
&lt;h2 id="wordpress"&gt;WordPress&lt;/h2&gt;
&lt;p&gt;WordPress 相对于百度空间是质的飞跃，正好借着新浪早期推广 SAE 的东风，免费使用了很长时间。
后来，SAE 不再免费，并逐渐提高收费标准，甚至出现“应用租金”的概念。
即使这样，因为博客访问量比较小，月度花费依然比租用虚拟机自己搭建博客便宜很多。
所以我的博客使用 WordPress 时间最长，从 2012 年到 2019 年。&lt;/p&gt;
&lt;p&gt;从使用 WordPress 开始，我的博客一直采用 &lt;a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh"&gt;署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)&lt;/a&gt; 协议。&lt;/p&gt;</description></item><item><title>统计数值预报产品生成时间：重采样</title><link>https://blog.perillaroc.wang/post/2020/05/2020-05-01-analytic-nwp-production-file-created-time-multi-bootstrap/</link><pubDate>Fri, 01 May 2020 15:48:07 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/05/2020-05-01-analytic-nwp-production-file-created-time-multi-bootstrap/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-11-analytic-nwp-production-file-created-time/"&gt;统计数值天气预报模式产品生成的典型时间&lt;/a&gt;》中介绍根据GRIB2文件创建时间统计产品生成的典型时间，并在《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time-bootstrapping/"&gt;统计数值预报产品生成时间：单个时效重采样&lt;/a&gt;》中介绍使用重采样技术统计单个时效的生成时间。&lt;/p&gt;
&lt;p&gt;本文基于这两篇文章，介绍如何使用自助法统计 &lt;strong&gt;所有&lt;/strong&gt; 时效产品的生成时间。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;载入需要使用的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pathlib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Path
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构造一个函数，批量获取文件创建时间&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;calculate_time&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_type,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_range,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_hours,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; forecast_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; forecast_hours:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_list&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_type,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;forecast_hour
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;in&lt;/span&gt; date_range
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(Path(f)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stat()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;st_mtime_ns) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date()) &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f, d &lt;span style="color:#f92672"&gt;in&lt;/span&gt; zip(file_list, date_range) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Series(ts, index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;date_range)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; s&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; int(forecast_hour&lt;span style="color:#f92672"&gt;.&lt;/span&gt;seconds&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3600&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; forecast_hour&lt;span style="color:#f92672"&gt;.&lt;/span&gt;days &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(s)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame(b)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;T
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; df
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构造起报时次列表&lt;/p&gt;</description></item><item><title>统计数值预报产品生成时间：单个时效重采样</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time-bootstrapping/</link><pubDate>Thu, 30 Apr 2020 21:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time-bootstrapping/</guid><description>&lt;p&gt;前一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time/"&gt;统计数值预报产品生成时间：单个时效&lt;/a&gt;》中介绍使用切尾均值作为产品生成的典型时间。对于单个时效的特定产品，即便将时间范围延长到一年，也仅有365个数据。
如果考虑系统升级可能带来的影响，可用的数据点就会更少。
数据量较少时，单纯使用均值会受到离群值的影响，所以前一篇文章中使用切尾均值作为典型时间。&lt;/p&gt;
&lt;p&gt;本文介绍另外一种思路。我们可以增加样本数，而自助法（Bootstrap）正是可以实现这一目标的工具。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;使用与《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time/"&gt;统计数值预报产品生成时间：单个时效&lt;/a&gt;》相同的数据，不再介绍。&lt;/p&gt;
&lt;h2 id="计算"&gt;计算&lt;/h2&gt;
&lt;p&gt;重采样 20 个样本，计算均值，并重复指定次数 &lt;code&gt;count&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;means &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; tnrange(count):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sampled_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sample(n&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, replace&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; means&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(sampled_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mean())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将所有值近似到秒&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bdf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame(means)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;applymap(&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; x: x&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ceil(&lt;span style="color:#e6db74"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bdf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;clock&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;04:50:53&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;04:56:04&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;05:02:03&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;04:48:51&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;04:53:21&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;计算采样均值的均值和方差&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bdf_mean &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bdf[&lt;span style="color:#e6db74"&gt;&amp;#34;clock&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;mean()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bdf_mean
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Timedelta(&amp;#39;0 days 04:53:28.601400&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bdf_std &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bdf[&lt;span style="color:#e6db74"&gt;&amp;#34;clock&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;std()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bdf_std
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Timedelta(&amp;#39;0 days 00:03:23.675759&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;计算 95% 分位数，即 95% 置信区间&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bdf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;quantile(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;0.95&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; numeric_only&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interpolation&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;nearest&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;qt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;clock 04:59:37
Name: 0.95, dtype: timedelta64[ns]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将 &lt;code&gt;bdf_mean + bdf_std&lt;/code&gt; 作为警告标准，将 &lt;code&gt;qt[&amp;quot;clock&amp;quot;]&lt;/code&gt; 作为延迟标准。
生成 &lt;code&gt;status&lt;/code&gt; 列保存对 &lt;code&gt;clock&lt;/code&gt; 列的分类。&lt;/p&gt;</description></item><item><title>统计数值预报产品生成时间：单个时效</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time/</link><pubDate>Thu, 30 Apr 2020 17:55:14 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-30-analytic-nwp-production-file-created-time-forecast-time/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-11-analytic-nwp-production-file-created-time/"&gt;统计数值天气预报模式产品生成的典型时间&lt;/a&gt;》中介绍如何根据GRIB2文件创建时间统计产品生成的典型时间，并在《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-19-bokeh-tutorial-adding-annotations/"&gt;Bokeh教程：添加标注&lt;/a&gt;》中介绍如何绘制单个时效的统计图形。&lt;/p&gt;
&lt;p&gt;本文在第二篇文章的基础上，再一次介绍如何绘制单个时效产品文件的生成情况，并增加额外的统计图形。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="获取数据"&gt;获取数据&lt;/h2&gt;
&lt;p&gt;载入需要使用到的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; tqdm.notebook &lt;span style="color:#f92672"&gt;import&lt;/span&gt; trange, tqdm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成时间列表，统计截止 2020 年 4 月 29 日之前 60 天的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;end_date &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-04-29 00:00:00&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;start_date &lt;span style="color:#f92672"&gt;=&lt;/span&gt; end_date &lt;span style="color:#f92672"&gt;-&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Timedelta(days&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date_range &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date_range(start_date, end_date, freq&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;D&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取文件列表&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_list&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;MODEL_A/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;240h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;in&lt;/span&gt; date_range 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取所有文件的创建时间&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pathlib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Path
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pbar &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tqdm(total&lt;span style="color:#f92672"&gt;=&lt;/span&gt;len(file_list))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f, d &lt;span style="color:#f92672"&gt;in&lt;/span&gt; zip(file_list, date_range):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ts&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(Path(f)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stat()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;st_mtime_ns) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(d&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date()))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pbar&lt;span style="color:#f92672"&gt;.&lt;/span&gt;update(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pbar&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Series(ts, name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;clock&amp;#34;&lt;/span&gt;, index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;date_range)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df &lt;span style="color:#f92672"&gt;=&lt;/span&gt; s&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_frame()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;clock&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;2020-02-29&lt;/td&gt;
					&lt;td&gt;05:28:28&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2020-03-01&lt;/td&gt;
					&lt;td&gt;05:22:41&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2020-03-02&lt;/td&gt;
					&lt;td&gt;05:09:02&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2020-03-03&lt;/td&gt;
					&lt;td&gt;04:39:53&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2020-03-04&lt;/td&gt;
					&lt;td&gt;05:30:53&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="切尾均值"&gt;切尾均值&lt;/h2&gt;
&lt;h3 id="计算"&gt;计算&lt;/h3&gt;
&lt;p&gt;与上一篇文章一样，计算切尾均值&lt;/p&gt;</description></item><item><title>GRIB笔记：使用 xarray 插值</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-29-grib-notebook-interpolation-with-nwpc-data/</link><pubDate>Wed, 29 Apr 2020 21:38:23 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-29-grib-notebook-interpolation-with-nwpc-data/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-29-xarray-guide-interpolation/"&gt;xarray指南：插值&lt;/a&gt;》中介绍使用 xarray 实现插值，本文介绍如何将该插值应用到 GRIB 2 文件中的要素场。&lt;/p&gt;
&lt;p&gt;本文使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库从本地 GRIB 2 文件中加载要素场。
nwpc-data 库介绍请浏览《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-23-nwpc-data-quickstart/"&gt;nwpc-data 库简介&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;加载需要的库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="站点插值"&gt;站点插值&lt;/h2&gt;
&lt;p&gt;获取 850hPa 温度场&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-04-26&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;24h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;PosixPath(&amp;#39;/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2020042521/ORIG/gmf.gra.2020042600024.grb2&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t850 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_file,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;pl&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t850
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray &amp;#39;t&amp;#39; (latitude: 720, longitude: 1440)&amp;gt;
array([[262.26335937, 262.28335938, 262.29335938, ..., 262.26335937,
 262.27335937, 262.30335938],
 ...,
 [243.63335937, 243.48335937, 243.64335938, ..., 243.56335938,
 243.53335938, 243.73335937]])
Coordinates:
 time datetime64[ns] 2020-04-26
 step timedelta64[ns] 1 days
 valid_time datetime64[ns] 2020-04-27
 pl float64 850.0
 * latitude (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
 * longitude (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
Attributes:
 GRIB_edition: 2
 ...skip...
 long_name: Temperature
 units: K
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;获取北京站温度，&lt;code&gt;[39.8, 116.4667]&lt;/code&gt;&lt;/p&gt;</description></item><item><title>xarray指南：插值</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-29-xarray-guide-interpolation/</link><pubDate>Wed, 29 Apr 2020 12:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-29-xarray-guide-interpolation/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/interpolation.html"&gt;Interpolating data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先导入需要使用到的库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;xarray 提供了灵活的插值程序，与索引有相似的接口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：&lt;code&gt;interp&lt;/code&gt; 需要安装 &lt;em&gt;scipy&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="标量和一维插值"&gt;标量和一维插值&lt;/h2&gt;
&lt;p&gt;插值 &lt;code&gt;DataArray&lt;/code&gt; 和标签索引 &lt;code&gt;DataArray&lt;/code&gt; 的工作方式类似。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sin(&lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reshape(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;, np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;space&amp;#34;&lt;/span&gt;, [&lt;span style="color:#ae81ff"&gt;0.1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;]),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (time: 4, space: 3)&amp;gt;
array([[ 0. , 0.29552021, 0.56464247],
 [ 0.78332691, 0.93203909, 0.99749499],
 [ 0.97384763, 0.86320937, 0.67546318],
 [ 0.42737988, 0.14112001, -0.15774569]])
Coordinates:
 * time (time) int64 0 1 2 3
 * space (space) float64 0.1 0.2 0.3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;标签查找&lt;/p&gt;</description></item><item><title>视界：HPC 2020 - ECMWF 新高性能计算机</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-28-hpc2020-ecmwfs-new-high-performance-computing-facility/</link><pubDate>Tue, 28 Apr 2020 11:36:05 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-28-hpc2020-ecmwfs-new-high-performance-computing-facility/</guid><description>&lt;p&gt;ECMWF 最新一期的 Newsletter 中介绍了它们的下一代高性能计算机 HPC2020。
虽然我们部门不负责 HPC 项目，但作为深度用户，即便我们未来也许会采用不一样的技术路线，也可以学习一下。&lt;/p&gt;
&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 163 - Spring 2020 中 Mike Hawkins 和 Isabella Weger 的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/163/computing/hpc2020-ecmwfs-new-high-performance-computing-facility"&gt;HPC2020 – ECMWF’s new High-Performance Computing Facility&lt;/a&gt;》，版权归原作者所有。
翻译底稿来自 Google 翻译和必应翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;ECMWF 的高性能计算设施（HPCF）是业务和科研活动的核心，平均每四到五年进行升级。
作为 HPC2020 项目的一部分，ECMWF 最近为新系统签订了合同，该系统由四个 Atos Sequana XH2000 群集组成，将提供由两个 Cray XC40 群集组成的当前系统大约五倍的性能。&lt;/p&gt;
&lt;h3 id="hpc2020-项目"&gt;HPC2020 项目&lt;/h3&gt;
&lt;p&gt;更换 ECMWF 的 HPCF 经过多年的努力。
HPC2020 项目最早于 2017 年启动，并获得了商务案例的开发和批准，随后于 2019 年底完成了国际采购。
HPC2020 的实施阶段于 2020 年初开始（图1）。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2020-04/NL-163_C2_Hawkins_Figure_1.svg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;图1 HPC2020 项目已从商务案例和采购阶段转到实施阶段。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id="商务案例和采购过程"&gt;商务案例和采购过程&lt;/h4&gt;
&lt;p&gt;ECMWF 的《2016-2025年战略》中设定的目标包括：
在最多两周之前对高影响天气做出精确的整体预报，并在未来四周之前预报大规模模式和天气变化（large-scale patterns and regime transitions），并在全球范围内提前一年预测异常情况。
这些雄心勃勃的目标只有通过适当的高性能计算能力才能实现。&lt;/p&gt;</description></item><item><title>视界：ECMWF的AI和机器学习</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-27-view-ai-and-machine-learning-ecmwf/</link><pubDate>Mon, 27 Apr 2020 13:00:42 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-27-view-ai-and-machine-learning-ecmwf/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 163 - Spring 2020 中 &lt;a href="https://www.ecmwf.int/en/about/who-we-are/staff-profiles/peter-dueben"&gt;Peter Dueben&lt;/a&gt; 的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/163/news/ai-and-machine-learning-ecmwf"&gt;AI and machine learning at ECMWF&lt;/a&gt;》，版权归原作者所有。
翻译底稿来自 Google 翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;ECMWF 当前正在大力支持人工智能和机器学习的应用，并鉴定此类应用如何改善中心的数值天气预报。
ECMWF 科学家每天使用的许多标准方法可以视为机器学习的示例。
但是，最近涌现出很多新方法，可能有潜力变革业务天气预报中心的工作。
这些方法包括使用深度神经网络，该网络可以从数据中学习复杂非线性系统的动态性。&lt;/p&gt;
&lt;h3 id="ecmwf-的机器学习现状"&gt;ECMWF 的机器学习现状&lt;/h3&gt;
&lt;p&gt;2020 年 1 月，ECMWF 召开一个内部研讨会，科学家和分析师展示与机器学习相关的项目。
此次会议旨在创造协作氛围，并加强使用或研究机器学习方法的科学家之间的交流。
这使 ECMWF 能有效地传播相关信息，包括即将到来的科学会议，训练机会，应用需求，以及 ECMWF 为机器学习应用准备的软硬件基础设施。
研讨会显示，ECMWF 大约有 25 个项目正在（或计划）以不同的方式使用机器学习。
正如图片中所展示的，应用分布在数值天气预报的整个工作流中。&lt;/p&gt;
&lt;p&gt;示例包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;卫星观测偏差订正&lt;/li&gt;
&lt;li&gt;学习资料同化的模型误差&lt;/li&gt;
&lt;li&gt;模拟模式组件以提高预报模式的计算效率&lt;/li&gt;
&lt;li&gt;模式输出的局地降尺度，以改善预报效果&lt;/li&gt;
&lt;li&gt;IT 基础设施的监控&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;应用的进展区别很大，从规划阶段的研究项目，例如再分析产品的监测和评估，一直到已在提供业务环境中提供的产品。
后者包括用于全球概率降水预报的 ecPoint 工具，以及从 SMOS 卫星检索观测数据同化土壤水分的工具。
此外，还与外部合作伙伴进行了一些涉及机器学习研究的积极协作。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2020-04/NL-163_News_11_Duben_Figure_1_NEW.svg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;应用领域。机器学习的潜在应用领域分布在数值天气预报的整个工作流程中。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="下一步计划"&gt;下一步计划&lt;/h3&gt;
&lt;p&gt;未来，由 ECMWF 和 EUMETSAT 联合开发的 European Weather Cloud 很可能将在机器学习工具开发方面扮演非常关键的角色。
对于 ECMWF 和成员国开展的工作也是如此。
拥有 Cloud 计算资源访问权限的研究人员可以很容易从数据归档中加载训练数据，并使用标准机器学习工具，类似 TensorFlow 和 Jupyter Notebooks。
这些工具与在 ECMWF 高性能计算机环境中使用的传统工具有很大的区别，它们通常更适应云计算环境。
当前，ECMWF 正在计划 European Weather Cloud 进行硬件升级，为现有基础架构添加足够的 GPU 资源，以支持机器学习应用程序的训练。&lt;/p&gt;</description></item><item><title>xarray指南：索引和选择数据 - 删除标签和维度</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-26-xarray-guide-indexing-dropping-labels-and-dims/</link><pubDate>Sun, 26 Apr 2020 20:45:58 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-26-xarray-guide-indexing-dropping-labels-and-dims/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/indexing.html"&gt;Indexing and selecting data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;drop_sel()&lt;/code&gt; 方法将返回一个新对象，该对象列出删除维度的索引标签：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rand(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;, pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date_range(&lt;span style="color:#e6db74"&gt;&amp;#34;2000-01-01&amp;#34;&lt;/span&gt;, periods&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;space&amp;#34;&lt;/span&gt;, [&lt;span style="color:#e6db74"&gt;&amp;#34;IA&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IL&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IN&amp;#34;&lt;/span&gt;]),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; da&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_dataset(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (space: 3, time: 4)
Coordinates:
 * time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
 * space (space) &amp;lt;U2 &amp;#39;IA&amp;#39; &amp;#39;IL&amp;#39; &amp;#39;IN&amp;#39;
Data variables:
 foo (time, space) float64 0.7553 0.4042 0.1169 ... 0.004518 0.6259
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds&lt;span style="color:#f92672"&gt;.&lt;/span&gt;drop_sel(space&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;IN&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IL&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (space: 1, time: 4)
Coordinates:
 * time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
 * space (space) &amp;lt;U2 &amp;#39;IA&amp;#39;
Data variables:
 foo (time, space) float64 0.7553 0.2052 0.6426 0.9223
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;drop_sel&lt;/code&gt; 既是 &lt;code&gt;Dataset&lt;/code&gt; 方法又是 &lt;code&gt;DataArray&lt;/code&gt; 方法。&lt;/p&gt;</description></item><item><title>Bokeh教程：链接与交互</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-25-bokeh-tutorial-linking-and-interactions/</link><pubDate>Sat, 25 Apr 2020 20:54:46 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-25-bokeh-tutorial-linking-and-interactions/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在我们已经从上一章知道了如何在一个布局中将多个图放置在一起，我们可以开始研究如何将不同的图链接到一起，或者如何将图链接到控件。&lt;/p&gt;
&lt;h2 id="链接交互"&gt;链接交互&lt;/h2&gt;
&lt;p&gt;可以链接不同 Bokeh 绘图之间的各种交互操作。
例如，可以链接两个（或多个）图的范围，以便在平移（或缩放）一个图或更改其范围时，其他图将一致更新。
也可以在两个图之间链接选择，以便在一个图上选择项目时，第二个图上的相应项目也将被选择。&lt;/p&gt;
&lt;h3 id="链接平移"&gt;链接平移&lt;/h3&gt;
&lt;p&gt;链接平移（当多个绘图的范围保持同步时）很容易用 Bokeh 拼写。
您只需在两个（或多个）绘图之间共享适当的范围对象。
以下示例显示了如何通过以各种方式链接三个图的范围来实现此目的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.layouts &lt;span style="color:#f92672"&gt;import&lt;/span&gt; gridplot
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; list(range(&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y0, y1, y2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; x, [&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;i &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; x], [abs(i&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; x]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plot_options &lt;span style="color:#f92672"&gt;=&lt;/span&gt; dict(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tools&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;pan,wheel_zoom&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建一个新绘图&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(&lt;span style="color:#f92672"&gt;**&lt;/span&gt;plot_options)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;circle(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y0, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;navy&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建另一个新绘图，并共享所有区域&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;s1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;x_range, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; y_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;s1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;y_range, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;plot_options
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s2&lt;span style="color:#f92672"&gt;.&lt;/span&gt;triangle(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y1, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;firebrick&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建一个新绘图，只共享一个区域&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s3 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;s1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;x_range, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;plot_options
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s3&lt;span style="color:#f92672"&gt;.&lt;/span&gt;square(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y2, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;olive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; gridplot([[s1, s2, s3]])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 显示绘图结果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(p)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/linking-and-interaction-linked-panning.png"&gt;
&lt;/figure&gt;

&lt;h3 id="链接刷"&gt;链接刷&lt;/h3&gt;
&lt;p&gt;链接选择以类似方式完成，通过在绘图之间共享数据源。
请注意，通常使用 &lt;code&gt;bokeh.plotting&lt;/code&gt; 和 &lt;code&gt;bokeh.charts&lt;/code&gt; 时会自动创建用于简单图的默认数据源。
但是，要共享数据源，我们必须手动创建并显式传递它们。
在下面的示例中对此进行了说明：&lt;/p&gt;</description></item><item><title>xarray指南：索引和选择数据 - 数据集索引</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-24-xarray-guide-dataset-indexing/</link><pubDate>Fri, 24 Apr 2020 21:10:14 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-24-xarray-guide-dataset-indexing/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/indexing.html"&gt;Indexing and selecting data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先导入需要使用到的库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_options(display_style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们还可以使用这些方法同时索引数据集中的所有变量，并返回一个新的数据集：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rand(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;, pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date_range(&lt;span style="color:#e6db74"&gt;&amp;#34;2000-01-01&amp;#34;&lt;/span&gt;, periods&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#34;space&amp;#34;&lt;/span&gt;, [&lt;span style="color:#e6db74"&gt;&amp;#34;IA&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IL&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IN&amp;#34;&lt;/span&gt;]),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; da&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_dataset(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;foo&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (space: 3, time: 4)
Coordinates:
 * time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
 * space (space) &amp;lt;U2 &amp;#39;IA&amp;#39; &amp;#39;IL&amp;#39; &amp;#39;IN&amp;#39;
Data variables:
 foo (time, space) float64 0.5041 0.2959 0.1441 ... 0.4777 0.2955 0.2749
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds&lt;span style="color:#f92672"&gt;.&lt;/span&gt;isel(space&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;], time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (space: 1, time: 1)
Coordinates:
 * time (time) datetime64[ns] 2000-01-01
 * space (space) &amp;lt;U2 &amp;#39;IA&amp;#39;
Data variables:
 foo (time, space) float64 0.5041
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sel(time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2000-01-01&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (space: 3)
Coordinates:
 time datetime64[ns] 2000-01-01
 * space (space) &amp;lt;U2 &amp;#39;IA&amp;#39; &amp;#39;IL&amp;#39; &amp;#39;IN&amp;#39;
Data variables:
 foo (space) float64 0.5041 0.2959 0.1441
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;不支持在数据集中进行位置索引，因为数据集中维度的顺序有些含糊（在不同数组之间可能会有所不同）。 但是，您可以使用维名称进行常规索引编制：&lt;/p&gt;</description></item><item><title>视界：ECMWF 产品数据存储（ECPDS）</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-23-view-the-ecmwf-production-data-store/</link><pubDate>Thu, 23 Apr 2020 22:10:43 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-23-view-the-ecmwf-production-data-store/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 159 - Sprint 2019 中的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/159/computing/ecmwf-production-data-store"&gt;The ECMWF Production Data Store&lt;/a&gt;》，版权归ECMWF所有。翻译底稿来自Google翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;为了确保将 ECMWF 的预报及时交付给成员国，合作国和其他用户，必须迅速收集来自全球的观测结果，并且必须可靠且在有限的时间内将预报结果交付给用户。
这些收集和分发过程曾经由单独的软件应用程序处理。
但是，这两项活动对数据服务（例如存储，传输，调度，安全性和监视）有相似的要求。
经过仔细考虑，ECMWF 在 2016 年决定将这两个应用程序合并为一个，即 ECMWF Production Data Store（ECPDS）。&lt;/p&gt;
&lt;p&gt;从那时起，ECMWF 内部开发了 ECPDS 软件，以支持 ECMWF 战略目标，同时牢记以下目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确保满足模式系统对更大数量（更高分辨率）和更多观测结果的不断发展的需求&lt;/li&gt;
&lt;li&gt;支持向我们的预报用户提供越来越多的变量&lt;/li&gt;
&lt;li&gt;加快我们的预报产品的分发速度&lt;/li&gt;
&lt;li&gt;使 ECMWF Data Services function 能够在世界气象组织（WMO）的框架内向世界各地的国家提供气象和水文服务产品，并向不断增长的商业客户提供产品&lt;/li&gt;
&lt;li&gt;向云计算基础架构过渡，以提高可扩展性和可靠性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文介绍使 ECPDS 满足这些目标的解决方案，并说明其主要功能。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-04/NL_159_-_C1_-_Gougeon_-_Figure_1ai-01.svg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;图1 ECPDS 主要组件的示意图。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="基本功能"&gt;基本功能&lt;/h3&gt;
&lt;p&gt;ECPDS 被设计为多用途存储库，以下称为数据存储（Data Store），可提供与数据相关的三种不同策略的服务（图1）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据采集：自动发现和检索来自数据提供者的观测数据&lt;/li&gt;
&lt;li&gt;数据分发：将气象产品自动分发给我们的成员国和合作国以及其他预报用户&lt;/li&gt;
&lt;li&gt;数据门户：提取气象产品并推送由远程站点获取的观测数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数据采集和数据分发是由 ECPDS 启动的主动服务，而数据门户是由远程站点的传入请求而触发的被动服务。
换句话说，数据门户服务提供对数据分发和数据采集服务的交互式访问。&lt;/p&gt;
&lt;p&gt;与传统的数据存储不同，ECPDS 不必将数据物理存储在持久存储库中，而是通过对数据提供者的元数据进行抓取和索引来像搜索引擎一样工作。
当然，ECPDS 可以在其数据存储中缓存数据。
这对于确保 ECPDS 中的数据可用性非常有用，不需要依赖于数据提供者的即时访问。
可以通过不同的机制将数据归档到数据存储中：&lt;/p&gt;</description></item><item><title>nwpc-data 库简介</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-23-nwpc-data-quickstart/</link><pubDate>Thu, 23 Apr 2020 16:20:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-23-nwpc-data-quickstart/</guid><description>&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 是为 GRAPES 系列模式开发的 GRIB 2 数据访问 python 工具库，提供检索要素场的便捷方法，支持气象局 CMA-PI 高性能计算机和二级存储。&lt;/p&gt;
&lt;p&gt;nwpc-data 内部使用 &lt;a href="https://github.com/ecmwf/eccodes-python"&gt;eccodes-python&lt;/a&gt; 解码 GRIB 2 文件。&lt;/p&gt;
&lt;p&gt;目前 nwpc-data 提供以下功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取业务系统产品文件路径&lt;/li&gt;
&lt;li&gt;从 GRIB 2 文件中检索要素场&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;nwpc-data 库正处于开发之中，后续会增加更多功能&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;从 Github 中下载最新的源代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://github.com/nwpc-oper/nwpc-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;pip&lt;/code&gt; 命令安装：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pip install .
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="cma-pi"&gt;CMA-PI&lt;/h3&gt;
&lt;p&gt;本项目已在中国气象局 CMA-PI 高性能计算机上进行测试，使用如下环境：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module load apps/eccodes/2.17.0/intel
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# module load compiler/intel/composer_xe_2018.1.163&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module load apps/python/3.6.3/gnu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装 nwpc-data 前需要单独安装依赖库 eccodes-python，可以使用下面的命令安装。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install --user /g11/wangdp/lib/python/attrs-19.3.0-py2.py3-none-any.whl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install --user /g11/wangdp/lib/python/eccodes_python-0.9.7-py2.py3-none-any.whl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CMA-PI 上已保存 nwpc-data 的最新版本，使用下面的命令将软件包安装到用户目录。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip install --user /g11/nwp_xp/wangdp/project/data/nwpc-data/nwpc-data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;首先导入需要使用的一些库。&lt;/p&gt;</description></item><item><title>使用Matplotlib动态绘制多个图形</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-22-draw-multi-plot-using-matplotlib/</link><pubDate>Wed, 22 Apr 2020 21:08:32 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-22-draw-multi-plot-using-matplotlib/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-21-grib-notebook-draw-cross-section-using-matplotlib/"&gt;GRIB笔记：使用Matplotlib绘制剖面图&lt;/a&gt;》介绍如何绘制剖面图。&lt;/p&gt;
&lt;p&gt;如果想要绘制多个剖面图进行对比，比如比较不同试验的差异，可以逐个绘制并使用 ImageMagick 等工具拼接到一块。
或者使用 &lt;code&gt;matplotlib.pyplot.subplots&lt;/code&gt; 在同一个画布中绘制多个图片。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 Matplotlib 绘制共享色表的多个图形，并根据输入数据的数量动态调整绘图个数。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;使用《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-21-grib-notebook-draw-cross-section-using-matplotlib/"&gt;GRIB笔记：使用Matplotlib绘制剖面图&lt;/a&gt;》中方法加载数据。&lt;/p&gt;
&lt;p&gt;为了后续函数调用，对数据进行简单的封装，包含名称、时间范围等描述信息。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grapes_1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;GRAPES&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: grapes_1_data,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;var&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;gh&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;length&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;starttime&amp;#34;&lt;/span&gt;: starttime,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;endtime&amp;#34;&lt;/span&gt;: endtime,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一共生成 5 个数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dataset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grapes_1, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grapes_2, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grapes_3, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grapes_4, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; test_1,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了使用统一的色表，需要为色表生成数值列表。取数据集中的最大值和最小值，分成 10 等分。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ceil(np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max([m&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max() &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; m &lt;span style="color:#f92672"&gt;in&lt;/span&gt; (d[&lt;span style="color:#e6db74"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; d &lt;span style="color:#f92672"&gt;in&lt;/span&gt; dataset)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;min_value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ceil(np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;min([m&lt;span style="color:#f92672"&gt;.&lt;/span&gt;min() &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; m &lt;span style="color:#f92672"&gt;in&lt;/span&gt; (d[&lt;span style="color:#e6db74"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;] &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; d &lt;span style="color:#f92672"&gt;in&lt;/span&gt; dataset)]))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;levels &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;linspace(min_value, max_value, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, dtype&lt;span style="color:#f92672"&gt;=&lt;/span&gt;int)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;levels
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;array([-56, -45, -34, -23, -12, -2, 8, 19, 30, 41])
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="绘制单个剖面图"&gt;绘制单个剖面图&lt;/h2&gt;
&lt;p&gt;将《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-21-grib-notebook-draw-cross-section-using-matplotlib/"&gt;GRIB笔记：使用Matplotlib绘制剖面图&lt;/a&gt;》中的绘图方法封装到一个函数中。&lt;/p&gt;</description></item><item><title>GRIB笔记：使用Matplotlib绘制剖面图</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-21-grib-notebook-draw-cross-section-using-matplotlib/</link><pubDate>Tue, 21 Apr 2020 21:55:54 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-21-grib-notebook-draw-cross-section-using-matplotlib/</guid><description>&lt;p&gt;之前在两篇文章中分别介绍使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 封装的 cfgrib 和 eccodes-python 接口加载绘制剖面图需要的数据。
文章中使用的接口将 GRIB 2 消息加载为 &lt;code&gt;xarray.DataArray&lt;/code&gt; 对象，并使用 xarray 集成的绘图接口绘制剖面图。但大部分应用都没有必要增加 xarray 库，虽然笔者强烈建议使用 xarray 库处理要素场数据。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-data&lt;/a&gt; 还提供对 eccodes-python 的另外一套封装函数，返回 eccodes-python 的 GRIB 2 消息对象，即代表 handler 的整数。&lt;/p&gt;
&lt;p&gt;本文介绍如何利用 nwpc-data 加载 GRIB 2 消息，并使用 matplotlib 绘制 Zonal Mean 偏差的剖面图。&lt;/p&gt;
&lt;h2 id="数据计算"&gt;数据计算&lt;/h2&gt;
&lt;p&gt;计算某个预报时效的月平均偏差可以通过计算每个预报时次的偏差再求偏差的平均得到。&lt;/p&gt;
&lt;h3 id="单个偏差"&gt;单个偏差&lt;/h3&gt;
&lt;p&gt;计算单个时次的偏差需要加载两个要素场并作差。&lt;/p&gt;
&lt;p&gt;下面的代码从 &lt;code&gt;fcstdata&lt;/code&gt; 和 &lt;code&gt;analdata&lt;/code&gt; 两个文件中加载层次为 &lt;code&gt;plev&lt;/code&gt; 的 &lt;code&gt;var&lt;/code&gt; 要素场，并将偏差累加到 &lt;code&gt;bias&lt;/code&gt; 中。
每个要素场都是形状为 &lt;code&gt;[121, 240]&lt;/code&gt; 的二维数组。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; eccodes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_message_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_message_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;fcstdata,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;var,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;isobaricInhPa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;plev,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fcst &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get_double_array(t, &lt;span style="color:#e6db74"&gt;&amp;#34;values&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fcst &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fcst&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reshape([&lt;span style="color:#ae81ff"&gt;121&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;240&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_message_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;analdata,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;var,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;isobaricInhPa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;plev,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anal &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get_double_array(t, &lt;span style="color:#e6db74"&gt;&amp;#34;values&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;anal &lt;span style="color:#f92672"&gt;=&lt;/span&gt; anal&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reshape([&lt;span style="color:#ae81ff"&gt;121&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;240&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bias &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; fcst &lt;span style="color:#f92672"&gt;-&lt;/span&gt; anal
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="所有层次偏差"&gt;所有层次偏差&lt;/h3&gt;
&lt;p&gt;将所有层次的要素场偏差保存到一个三维数组中。
该数组使用下面的代码初始化，其中 &lt;code&gt;plevs&lt;/code&gt; 是层次列表。&lt;/p&gt;</description></item><item><title>Bokeh教程：演示布局</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-20-bokeh-tutorial-presentation-layouts/</link><pubDate>Mon, 20 Apr 2020 20:52:46 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-20-bokeh-tutorial-presentation-layouts/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在前面的章节中，我们已开始学习如何使用不同类型的数据创建单个绘图。
但是我们经常想要绘制不止一幅图。
Bokeh 绘图可以独立嵌入在 HTML 文档中，但使用 Bokeh 内置布局将多个绘图合并通常更容易。
我们将在本章节中学习如何实现。&lt;/p&gt;
&lt;p&gt;载入 Bokeh。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面定义我们将在示例中使用的一些数据变量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; list(range(&lt;span style="color:#ae81ff"&gt;11&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y0, y1, y2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; x, [&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;i &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; x], [abs(i&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; x]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="行和列"&gt;行和列&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;bokeh.layouts&lt;/code&gt; 模块提供 &lt;code&gt;row&lt;/code&gt; 和 &lt;code&gt;column&lt;/code&gt; 函数用于将绘图安排在垂直和水平布局中。
下面示例将三个绘图排列成一行。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.layouts &lt;span style="color:#f92672"&gt;import&lt;/span&gt; row
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建一个新绘图&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;circle(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y0,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;navy&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alpha&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 创建另一个&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; plot_height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s2&lt;span style="color:#f92672"&gt;.&lt;/span&gt;triangle(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y1, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;firebrick&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alpha&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 再创建一个&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s3 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; height&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;250&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s3&lt;span style="color:#f92672"&gt;.&lt;/span&gt;square(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y2, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;olive&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; alpha&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 将结果显示在一行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(row(s1, s2, s3))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/presetation-layout-row.png"&gt;
&lt;/figure&gt;

&lt;h2 id="网格绘图"&gt;网格绘图&lt;/h2&gt;
&lt;p&gt;Bokeh 在 &lt;code&gt;bokeh.layouts&lt;/code&gt; 中提供 &lt;code&gt;gridplot&lt;/code&gt; 用于将绘图排列成网格。
下面是一个示例。&lt;/p&gt;</description></item><item><title>Bokeh教程：添加标注</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-19-bokeh-tutorial-adding-annotations/</link><pubDate>Sun, 19 Apr 2020 08:46:02 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-19-bokeh-tutorial-adding-annotations/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;有时我们想要添加视觉提示（边界线，阴影区域，标签和箭头等等），以突出某些特性。
Bokeh 有几种可用的标注类型。
通常，为了添加标注，我们直接创建“底层”标注对象，使用 &lt;code&gt;add_layout&lt;/code&gt; 添加到图形中。
让我们看一些具体的示例。&lt;/p&gt;
&lt;h2 id="spans"&gt;Spans&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Spans&lt;/code&gt; 是 “无限” 的竖直或水平直线。
创建它们时，需要指定想要跨越的维度（例如，&lt;code&gt;width&lt;/code&gt; 或 &lt;code&gt;height&lt;/code&gt;），任何线条属性和线条在被绘制的维度上的位置。
让我们看一个示例，添加两条水平直线到一个简单的绘图中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.models.annotations &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Span
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;linspace(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sin(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; figure(y_range&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;line(x, y)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;upper &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Span(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dimension&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; line_color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;olive&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; line_width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_layout(upper)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lower &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Span(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location&lt;span style="color:#f92672"&gt;=-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dimension&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;width&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; line_color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;firebrick&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; line_width&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_layout(lower)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;show(p)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/annotations-span-line.png"&gt;
&lt;/figure&gt;

&lt;h2 id="box-annotations"&gt;Box Annotations&lt;/h2&gt;
&lt;p&gt;有时想要画一个阴影方框来突出绘图中的某个区域。
可以通过 &lt;code&gt;BoxAnnotation&lt;/code&gt; 实现，使用下面的坐标属性来配置：&lt;/p&gt;</description></item><item><title>GRIB笔记：使用eccodes-python加载垂直剖面图数据</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-18-grib-notebook-load-section-data-using-eccodes-python/</link><pubDate>Sat, 18 Apr 2020 10:52:49 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-18-grib-notebook-load-section-data-using-eccodes-python/</guid><description>&lt;p&gt;上一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-17-grib-notebook-load-section-data-using-cfgrib/"&gt;GRIB笔记：使用cfgrib加载垂直剖面图数据&lt;/a&gt;》
介绍使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 封装的 cfgrib 接口加载垂直剖面图数据。
但笔者尚未找到使用 cfgrib 加载全部等压面层数据的方法。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 封装的 eccodes-python 接口加载绘制垂直剖面图需要的数据。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;使用 GRAPES GFS 模式的预报数据绘制温度场的垂直剖面图。
对于 GRAPES 模式来说，某个预报时效所有层次的变量都保存到同一个文件中，所以从单个文件中就能获取绘制剖面图需要的所有数据。&lt;/p&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 提供的工具获取 CMA 二级存储上的文件路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2020031800&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;105h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;/sstorage1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2020031721/ORIG/gmf.gra.2020031800105.grb2
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="加载等压面层数据"&gt;加载等压面层数据&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 提供封装 eccodes-python 的接口，从本地文件中获取要素场并返回 &lt;code&gt;xarray.DataArray&lt;/code&gt; 对象。
具体实现方法请参考《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-31-build-xarray-dataarray-from-eccodes-message/"&gt;从ecCodes的GRIB2消息构建xarray对象&lt;/a&gt;》。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.eccodes &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;short_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;level_type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pl&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;short_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;level_type,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_dim&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;isobaricInhPa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Filtering: 100%|██████████| 837/837 [00:00&amp;lt;00:00, 1877.44it/s]
Creating DataArrays: 100%|██████████| 40/40 [00:12&amp;lt;00:00, 3.13it/s]
concat DataArrays...
&amp;lt;xarray.DataArray &amp;#39;t&amp;#39; (isobaricInhPa: 40, latitude: 720, longitude: 1440)&amp;gt;
array([[[245.73582031, 245.72582031, 245.74582031, ..., 245.73582031,
 ...skip...
 236.2610625 , 236.2610625 ]]])
Coordinates:
 step timedelta64[ns] 4 days 09:00:00
 time datetime64[ns] 2020-03-18
 * latitude (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
 * longitude (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
 * isobaricInhPa (isobaricInhPa) float64 1e+03 975.0 950.0 ... 0.5 0.2 0.1
Attributes:
 GRIB_edition: 2
 ...skip...
 long_name: Temperature
 units: K
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;level_type&lt;/code&gt; 是层次类型，&lt;code&gt;pl&lt;/code&gt; 表示等压面层，在函数内部被解析为层次类型的过滤条件 &lt;code&gt;{ &amp;quot;typeOfFirstFixedSurface&amp;quot;: 100 }&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>GRIB笔记：使用cfgrib加载垂直剖面图数据</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-17-grib-notebook-load-section-data-using-cfgrib/</link><pubDate>Fri, 17 Apr 2020 21:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-17-grib-notebook-load-section-data-using-cfgrib/</guid><description>&lt;p&gt;本文介绍如何使用 cfgrib 加载绘制垂直剖面图需要的数据。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;使用 GRAPES GFS 模式的预报数据绘制温度场的垂直剖面图。
对于 GRAPES 模式来说，某个预报时效所有层次的变量都保存到同一个文件中，所以从单个文件中就能获取绘制剖面图需要的所有数据。&lt;/p&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 提供的工具获取 CMA 二级存储上的文件路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2020031800&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;105h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;/sstorage1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2020031721/ORIG/gmf.gra.2020031800105.grb2
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="加载等压面层数据"&gt;加载等压面层数据&lt;/h2&gt;
&lt;p&gt;使用 cfgrib 加载等压面的温度场需要设置筛选条件。
具体方法请参考《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-02-grib-notebook-get-field-from-grib2-file/"&gt;GRIB笔记：从GRIB 2文件中加载单个要素场&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;本文使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 封装的函数获取温度场。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.cfgrib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;short_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;level_type &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;isobaricInhPa&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;file_path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;short_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;level_type,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;field
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray &amp;#39;t&amp;#39; (isobaricInhPa: 36, latitude: 720, longitude: 1440)&amp;gt;
[37324800 values with dtype=float32]
Coordinates:
 time datetime64[ns] ...
 step timedelta64[ns] ...
 * isobaricInhPa (isobaricInhPa) int64 1000 975 950 925 900 850 ... 5 4 3 2 1
 * latitude (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
 * longitude (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
 valid_time datetime64[ns] ...
Attributes:
 GRIB_paramId: 130
 GRIB_shortName: t
 ...skip...
 long_name: Temperature
 units: K
 standard_name: air_temperature
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以看到我们加载了 1000hPa 到 1hPa 共 36 个温度场。&lt;/p&gt;</description></item><item><title>xarray指南：合并数据 - 多维度合并</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-16-xarray-guide-combining-multi/</link><pubDate>Thu, 16 Apr 2020 20:50:46 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-16-xarray-guide-combining-multi/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/combining.html"&gt;Combining data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何使用 xarray 实现多纬度合并。&lt;/p&gt;
&lt;h2 id="注意"&gt;注意&lt;/h2&gt;
&lt;p&gt;当前有三个名称相似的合并函数：&lt;code&gt;auto_combine()&lt;/code&gt;，&lt;code&gt;combine_by_coords()&lt;/code&gt; 和 &lt;code&gt;combine_nested()&lt;/code&gt;。
这是因为不建议使用 &lt;code&gt;auto_combine&lt;/code&gt;，而推荐使用其它两个更通用的函数。
如果当前代码依赖 &lt;code&gt;auto_combine&lt;/code&gt;，那么可以使用 &lt;code&gt;combine_nested&lt;/code&gt; 获得相似的功能。&lt;/p&gt;
&lt;h2 id="沿多维度合并"&gt;沿多维度合并&lt;/h2&gt;
&lt;p&gt;为了沿多个维度合并多个对象，xarray 提供 &lt;code&gt;combine_nested()&lt;/code&gt; 和 &lt;code&gt;combine_by_coords()&lt;/code&gt;。
这些函数在不同变量中组合使用 &lt;code&gt;concat&lt;/code&gt; 和 &lt;code&gt;merge&lt;/code&gt;，将多个对象合并为一个。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;combine_nested()&lt;/code&gt; 需要指定变量合并的顺序，而 &lt;code&gt;combine_by_coords()&lt;/code&gt; 尝试从数据的坐标中自动推断合并顺序。&lt;/p&gt;
&lt;p&gt;当事先知道每个对象之间的空间关系时，&lt;code&gt;combine_nested()&lt;/code&gt; 很有用。
数据集必须按照嵌套列表形式提供，指示它们的相对位置和顺序。
一个常见的任务是从并行仿真中收集数据，其中每个处理器将数据写入到单独的文件中。
将一个域分解为 4 个部分（沿 x 和 y 轴各 2 个部分），需要将数据集组织成一个双嵌套列表，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;temperature&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;randint(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dims&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray &amp;#39;temperature&amp;#39; (x: 2, y: 2)&amp;gt;
array([[3, 4],
 [0, 3]])
Dimensions without coordinates: x, y
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds_grid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[arr, arr], [arr, arr]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;combine_nested(ds_grid, concat_dim&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray &amp;#39;temperature&amp;#39; (x: 4, y: 4)&amp;gt;
array([[3, 4, 3, 4],
 [0, 3, 0, 3],
 [3, 4, 3, 4],
 [0, 3, 0, 3]])
Dimensions without coordinates: x, y
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;combine_nested()&lt;/code&gt; 还可用于显式合并不同变量的数据集。
例如如果我们有 4 个数据集，它们被划分为两个时间并包含两个不同的变量，则可以向 &lt;code&gt;concat_dim&lt;/code&gt; 传递 &lt;code&gt;None&lt;/code&gt;，指定我们希望使用 &lt;code&gt;merge&lt;/code&gt; 的嵌套列表中的维度，而不是 &lt;code&gt;concat&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>xarray指南：合并数据 - 合并</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-15-xarray-guide-combining-merge/</link><pubDate>Wed, 15 Apr 2020 21:19:09 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-15-xarray-guide-combining-merge/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/combining.html"&gt;Combining data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何使用 xarray 实现不同变量或索引的合并。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;本文使用《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-14-xarray-guide-combining-concatenate/"&gt;xarray指南：合并数据 - 连接&lt;/a&gt;》中的数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ds
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (x: 2, y: 3)
Coordinates:
 * x (x) &amp;lt;U1 &amp;#39;a&amp;#39; &amp;#39;b&amp;#39;
 * y (y) int64 10 20 30
Data variables:
 foo (x, y) float64 0.8927 0.7334 -0.9644 0.05414 -2.151 -1.543
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="merge"&gt;Merge&lt;/h2&gt;
&lt;p&gt;想要合并多个 &lt;code&gt;DataArray&lt;/code&gt; 和/或 &lt;code&gt;Dataset&lt;/code&gt; 对象的变量和坐标，请使用 &lt;code&gt;merge()&lt;/code&gt;。
可以合并 &lt;code&gt;Dataset&lt;/code&gt;、&lt;code&gt;DataArray&lt;/code&gt; 的列表，或者可以转换成 &lt;code&gt;DataArray&lt;/code&gt; 的对象的字典。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;merge([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ds, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ds&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rename({&lt;span style="color:#e6db74"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;}),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: (x: 2, y: 3)
Coordinates:
 * x (x) &amp;lt;U1 &amp;#39;a&amp;#39; &amp;#39;b&amp;#39;
 * y (y) int64 10 20 30
Data variables:
 foo (x, y) float64 0.8927 0.7334 -0.9644 0.05414 -2.151 -1.543
 bar (x, y) float64 0.8927 0.7334 -0.9644 0.05414 -2.151 -1.543
&lt;/code&gt;&lt;/pre&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;merge([xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(n, name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;var&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; n) &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; n &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.Dataset&amp;gt;
Dimensions: ()
Data variables:
 var0 int64 0
 var1 int64 1
 var2 int64 2
 var3 int64 3
 var4 int64 4
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果合并另一个数据集（或包括数据数组对象的字典），默认情况下，结果数据集将在所有索引坐标的&lt;strong&gt;并集&lt;/strong&gt;上对齐&lt;/p&gt;</description></item><item><title>xarray指南：合并数据 - 连接</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-14-xarray-guide-combining-concatenate/</link><pubDate>Tue, 14 Apr 2020 20:48:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-14-xarray-guide-combining-concatenate/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/combining.html"&gt;Combining data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文介绍如何使用 xarray 实现沿单个纬度合并 &lt;code&gt;DataArray&lt;/code&gt; 或 &lt;code&gt;Dataset&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;有关沿单个维度组合数据集或数据数组的信息，请参阅 concatenate。&lt;/li&gt;
&lt;li&gt;有关合并具有不同变量的数据集，请参见 merge。&lt;/li&gt;
&lt;li&gt;有关合并具有不同索引或缺失值的数据集或数据数组的信息，请参见 combine。&lt;/li&gt;
&lt;li&gt;有关沿多个维度组合数据集或数据数组的信息，请参见 combining.multi。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;加载需要使用到的库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_options(display_style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="concatenate"&gt;Concatenate&lt;/h2&gt;
&lt;p&gt;想要沿着已经存在或新的维度将数组合并为一个更大的数组，可以使用 &lt;code&gt;concat()&lt;/code&gt;。
&lt;code&gt;concat&lt;/code&gt; 接收一个可迭代的 &lt;code&gt;DataArray&lt;/code&gt; 或 &lt;code&gt;Dataset&lt;/code&gt; 对象，以及一个维度名称，沿着该维度进行连接。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;randn(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;, [&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;]), 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;, [&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;arr[:, :&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (x: 2, y: 1)&amp;gt;
array([[0.89269944],
 [0.05413846]])
Coordinates:
 * x (x) &amp;lt;U1 &amp;#39;a&amp;#39; &amp;#39;b&amp;#39;
 * y (y) int64 10
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;类似于使用 &lt;code&gt;np.concatenate&lt;/code&gt; 的方式&lt;/p&gt;</description></item><item><title>Bokeh教程：数据源和转换</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-12-bokeh-tutorial-data-sources-and-transformations/</link><pubDate>Sun, 12 Apr 2020 20:30:38 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-12-bokeh-tutorial-data-sources-and-transformations/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="导入和安装"&gt;导入和安装&lt;/h2&gt;
&lt;p&gt;首先进行标准导入&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本章节使用Bokeh示例数据。 如果尚未下载，可以通过运行以下命令下载：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; bokeh.sampledata
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bokeh&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sampledata&lt;span style="color:#f92672"&gt;.&lt;/span&gt;download()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;我们已经看到 Bokeh 如何与 Python 列表，NumPy 数组，Pandas series 等一起很好地工作。
在底层，这些输入被转换为 Bokeh &lt;code&gt;ColumnDataSource&lt;/code&gt;。
此数据类型是 Bokeh 中使用的核心数据源对象。
尽管 Bokeh 经常透明地为我们创建它们，但有时显式创建它们很有用。&lt;/p&gt;
&lt;p&gt;在后面的部分中，我们将看到诸如悬停工具提示，计算转换和 CustomJS交互之类使用 &lt;code&gt;ColumnDataSource&lt;/code&gt; 的功能，因此让我们快速浏览一下。&lt;/p&gt;
&lt;h2 id="使用-python-字典创建"&gt;使用 Python 字典创建&lt;/h2&gt;
&lt;p&gt;可以从 &lt;code&gt;bokeh.models&lt;/code&gt; 中导入 &lt;code&gt;ColumnDataSource&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.models &lt;span style="color:#f92672"&gt;import&lt;/span&gt; ColumnDataSource
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ColumnDataSource&lt;/code&gt; 是列名（字符串）到值序列的映射。
这是一个简单的例子。
通过传递带有字符串键和简单 Python 列表作为值的 Python &lt;code&gt;dict&lt;/code&gt; 提供映射。 值也可以是 NumPy 数组或 Pandas 序列。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;注意：&lt;code&gt;ColumnDataSource&lt;/code&gt; 中的所有列必须始终长度相同。&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ColumnDataSource(data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt; : [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;y&amp;#39;&lt;/span&gt; : [&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;到现在为止，我们已经通过直接传入文本列表或数据数组来调用诸如 &lt;code&gt;p.circle&lt;/code&gt; 之类的函数。
当我们这样做时，Bokeh 会自动为我们创建一个 &lt;code&gt; ColumnDataSource&lt;/code&gt;。
但是可以通过将它作为 &lt;code&gt;source&lt;/code&gt; 参数传递给 glyph 方法来显式指定一个 &lt;code&gt; ColumnDataSource&lt;/code&gt;。
每当我们这样做时，如果想要一个属性（例如 &lt;code&gt;x&lt;/code&gt; 或 &lt;code&gt;y&lt;/code&gt; 或 &lt;code&gt;fill_color&lt;/code&gt;）有一系列值，则需要传递想用于属性的 &lt;em&gt;&lt;strong&gt;列名&lt;/strong&gt;&lt;/em&gt; ：&lt;/p&gt;</description></item><item><title>Bokeh教程：样式和主题</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-12-bokeh-tutorial-style-and-theming/</link><pubDate>Sun, 12 Apr 2020 15:34:51 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-12-bokeh-tutorial-style-and-theming/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在本章中，我们将学习如何配置绘图的各种视觉效果，以及如何查找有关可配置内容的更多信息。&lt;/p&gt;
&lt;h2 id="导入和安装"&gt;导入和安装&lt;/h2&gt;
&lt;p&gt;首先，进行标准导入&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本 notebook 使用 Bokeh 示例数据。 如果尚未下载，可以运行以下命令进行下载：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; bokeh.sampledata
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bokeh&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sampledata&lt;span style="color:#f92672"&gt;.&lt;/span&gt;download()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在正式开始前，我们首先描述在 Bokeh 中如何指定颜色和属性。&lt;/p&gt;
&lt;h2 id="颜色"&gt;颜色&lt;/h2&gt;
&lt;p&gt;您可能需要在许多地方设置颜色。
Bokeh 可以通过多种不同的方式接受颜色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任意 &lt;a href="https://www.w3schools.com/colors/colors_names.asp"&gt;140 named HTML/CSS colors&lt;/a&gt;， 例如&lt;code&gt;'green'&lt;/code&gt;, &lt;code&gt;'indigo'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;RGB(A) 十六进制值，例如 &lt;code&gt;'#FF0000'&lt;/code&gt;, &lt;code&gt;'#44444444'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;3元组整数 &lt;em&gt;(r,g,b)&lt;/em&gt;，0-255之间&lt;/li&gt;
&lt;li&gt;4元组 &lt;em&gt;(r,g,b,a)&lt;/em&gt; ，其中 &lt;em&gt;r&lt;/em&gt; , &lt;em&gt;g&lt;/em&gt; , &lt;em&gt;b&lt;/em&gt; 是0-255之间的证书，&lt;em&gt;a&lt;/em&gt; 是0-1之间的浮点数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="属性"&gt;属性&lt;/h2&gt;
&lt;p&gt;无论如何创建 Bokeh 图形，都可以通过在构成结果图像的 Bokeh 对象上设置属性来实现定制视觉外观样式。
视觉属性分为三种：线条，填充和文本属性。
有关代码和示例的完整信息，请参见用户指南中的 &lt;a href="https://bokeh.pydata.org/en/latest/docs/user_guide/styling.html"&gt;样式视觉属性&lt;/a&gt;
章节。&lt;/p&gt;
&lt;h3 id="线条属性"&gt;线条属性&lt;/h3&gt;
&lt;p&gt;设置线条的视觉外观。最常用的属性是 &lt;code&gt;line_color&lt;/code&gt;, &lt;code&gt;line_alpha&lt;/code&gt;, &lt;code&gt;line_width&lt;/code&gt; 和 &lt;code&gt;line_dash&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="填充属性"&gt;填充属性&lt;/h3&gt;
&lt;p&gt;设置填充区域的视觉外观：&lt;code&gt;fill_color&lt;/code&gt; 和 &lt;code&gt;fill_alpha&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>统计数值天气预报模式产品生成的典型时间</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-11-analytic-nwp-production-file-created-time/</link><pubDate>Sat, 11 Apr 2020 21:20:04 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-11-analytic-nwp-production-file-created-time/</guid><description>&lt;p&gt;在之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-27-analytic-nwp-model-production-time/"&gt;统计数值天气预报模式产品生成时间&lt;/a&gt;》中展示使用产品生成消息数据绘制逐日的产品生成情况。&lt;/p&gt;
&lt;p&gt;其实如果文件在归档后没有改动，仅用产品文件本身也可以实现类似的功能。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 GRIB2 文件的创建时间来统计产品生成的典型时间。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="预先准备"&gt;预先准备&lt;/h2&gt;
&lt;p&gt;首先导入需要的库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="文件创建时间"&gt;文件创建时间&lt;/h2&gt;
&lt;p&gt;Linux 中文件的创建时间等于修改时间，本文假定产品文件在生成后不会被修改。&lt;/p&gt;
&lt;p&gt;下面的代码将获取文件修改时间，返回 &lt;code&gt;pandas.Timestamp&lt;/code&gt; 格式，其中 &lt;code&gt;f&lt;/code&gt; 是文件路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; pathlib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Path
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;created_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(Path(f)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stat()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;st_mtime_ns)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="获取单个时效的数据"&gt;获取单个时效的数据&lt;/h2&gt;
&lt;p&gt;本文统计 3 月 1 日到 3 月 31 日共一个月的 GRIB 2 文件创建时间。&lt;/p&gt;
&lt;p&gt;下面使用&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt;获取 MODEL A 的3月份逐日 00 时次 000 时效的 GRIB 2 文件路径。并使用上面的代码获取文件创建时间，并减去对应的日期，返回 &lt;code&gt;pandas.Timedelta&lt;/code&gt; 对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;date_range &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date_range(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-03-01 00:00:00&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;2020-03-31 00:00:00&amp;#34;&lt;/span&gt;, freq&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;D&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_list&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;model_A/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;0h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; t
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;in&lt;/span&gt; date_range 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;to_datetime(Path(f)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stat()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;st_mtime_ns) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; d &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f, d &lt;span style="color:#f92672"&gt;in&lt;/span&gt; zip(file_list, date_range) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Series(ts, index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;date_range)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;2020-03-01 04:12:38
2020-03-02 04:16:45
2020-03-03 04:16:48
2020-03-04 04:37:14
2020-03-05 04:19:14
2020-03-06 04:24:41
2020-03-07 04:16:53
2020-03-08 04:20:53
2020-03-09 04:20:38
2020-03-10 04:22:12
2020-03-11 04:17:40
2020-03-12 04:19:38
2020-03-13 04:18:30
2020-03-14 04:19:57
2020-03-15 04:18:08
2020-03-16 04:18:40
2020-03-17 04:26:59
2020-03-18 04:19:53
2020-03-19 04:21:08
2020-03-20 04:22:10
2020-03-21 04:22:52
2020-03-22 04:17:04
2020-03-23 04:24:48
2020-03-24 04:25:38
2020-03-25 04:20:53
2020-03-26 04:21:02
2020-03-27 05:31:12
2020-03-28 04:20:12
2020-03-29 04:18:17
2020-03-30 04:21:32
2020-03-31 04:22:06
Freq: D, dtype: timedelta64[ns]
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="探索数据"&gt;探索数据&lt;/h2&gt;
&lt;p&gt;使用 Bokeh 绘制 000 时效文件生成时间的折线。&lt;/p&gt;</description></item><item><title>xarray指南：索引和选择数据 - 最近邻查找</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-10-xarray-guide-nearest-neighbor-lookups/</link><pubDate>Fri, 10 Apr 2020 22:10:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-10-xarray-guide-nearest-neighbor-lookups/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/indexing.html"&gt;Indexing and selecting data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文使用之前文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-09-xarray-guide-indexing-a/"&gt;xarray指南：索引和选择数据 - 位置和名称索引&lt;/a&gt;》中的示例数据，不再重复介绍。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 xarray 实现最近邻查找。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;基于标签的选择方法 &lt;code&gt;sel()&lt;/code&gt;，&lt;code&gt;reindex()&lt;/code&gt; 和 &lt;code&gt;reindex_like()&lt;/code&gt; 都支持 &lt;code&gt;method&lt;/code&gt; 和 &lt;code&gt;tolerance&lt;/code&gt; 关键字参数。
&lt;code&gt;method&lt;/code&gt; 参数允许使用 &lt;code&gt;pad&lt;/code&gt;，&lt;code&gt;backfill&lt;/code&gt; 或 &lt;code&gt;nearest&lt;/code&gt; 方法启用最近邻（inexact）查找：&lt;/p&gt;
&lt;p&gt;构造一个一维数组&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [(&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;, [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;])]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (x: 3)&amp;gt;
array([1, 2, 3])
Coordinates:
 * x (x) int64 0 1 2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;选择给定坐标的最近邻点&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;da&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sel(x&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1.1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1.9&lt;/span&gt;], method&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;nearest&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (x: 2)&amp;gt;
array([2, 3])
Coordinates:
 * x (x) int64 1 2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用 &lt;code&gt;backfill&lt;/code&gt; 选择下一个有效值&lt;/p&gt;</description></item><item><title>xarray指南：索引和选择数据 - 位置和名称索引</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-09-xarray-guide-indexing-a/</link><pubDate>Thu, 09 Apr 2020 22:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-09-xarray-guide-indexing-a/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/indexing.html"&gt;Indexing and selecting data&lt;/a&gt; 的部分内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先导入需要的库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_options(display_style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了在实战中学习，使用 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 库加载一个示例数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.grib.cfgrib &lt;span style="color:#f92672"&gt;import&lt;/span&gt; load_field_from_file
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_data.data_finder &lt;span style="color:#f92672"&gt;import&lt;/span&gt; find_local_file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;加载 850hPa 温度场&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t850 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_field_from_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;find_local_file(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_gfs_gmf/grib2/orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2020031800&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;105h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;t&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;isobaricInhPa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;850&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t850
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray &amp;#39;t&amp;#39; (latitude: 720, longitude: 1440)&amp;gt;
[1036800 values with dtype=float32]
Coordinates:
 time datetime64[ns] ...
 step timedelta64[ns] ...
 isobaricInhPa int64 ...
 * latitude (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
 * longitude (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
 valid_time datetime64[ns] ...
Attributes:
 GRIB_paramId: 130
 GRIB_shortName: t
 GRIB_units: K
 GRIB_name: Temperature
 GRIB_cfName: air_temperature
 GRIB_cfVarName: t
 GRIB_dataType: fc
 GRIB_missingValue: 9999
 GRIB_numberOfPoints: 1036800
 GRIB_typeOfLevel: isobaricInhPa
 GRIB_NV: 0
 GRIB_stepUnits: 1
 GRIB_stepType: instant
 GRIB_gridType: regular_ll
 GRIB_gridDefinitionDescription: Latitude/longitude 
 GRIB_Nx: 1440
 GRIB_iDirectionIncrementInDegrees: 0.25
 GRIB_iScansNegatively: 0
 GRIB_longitudeOfFirstGridPointInDegrees: 0.0
 GRIB_longitudeOfLastGridPointInDegrees: 359.75
 GRIB_Ny: 720
 GRIB_jDirectionIncrementInDegrees: 0.25
 GRIB_jPointsAreConsecutive: 0
 GRIB_jScansPositively: 0
 GRIB_latitudeOfFirstGridPointInDegrees: 89.875
 GRIB_latitudeOfLastGridPointInDegrees: -89.875
 long_name: Temperature
 units: K
 standard_name: air_temperature
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;xarray 提供了非常灵活的索引功能，结合 NumPy 和 pandas 的优秀特性来进行数据选择。&lt;/p&gt;</description></item><item><title>xarray指南：数据结构</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-07-xarray-guide-data-structure/</link><pubDate>Tue, 07 Apr 2020 17:34:59 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-07-xarray-guide-data-structure/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 xarray 官方文档 &lt;a href="http://xarray.pydata.org/en/stable/data-structures.html"&gt;Data Structures&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;开始之前，先导入需要的包。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set_options(display_style&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="dataarray"&gt;DataArray&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;xarray.DataArray&lt;/code&gt; 是 xarray 实现的带标签的多维度数组，有下面几个关键属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;：保存数组值的 &lt;code&gt;numpy.ndarray&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dims&lt;/code&gt;：每个轴的名称，例如 &lt;code&gt;('x', 'y', 'z')&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coords&lt;/code&gt;：类似字典的数组容器（coordinates），标记每个点。例如数字、日期时间对象或字符串的一维数组&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attrs&lt;/code&gt;：保存任意元数据（attributes）的 &lt;code&gt;dict&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;xarray 使用 &lt;code&gt;dims&lt;/code&gt; 和 &lt;code&gt;coords&lt;/code&gt; 实现其核心元数据感知操作。
维度（Dimensions）提供 xarray 使用的名称，代替许多 numpy 函数中的 &lt;code&gt;axis&lt;/code&gt; 参数。
坐标（Coordinates）类似 Pandas &lt;code&gt;DataFrame&lt;/code&gt; 或 &lt;code&gt;Series&lt;/code&gt; 上的索引功能，实现基于标签的快速索引和对齐功能。&lt;/p&gt;
&lt;p&gt;DataArray 对象也可以有名称，并通过 &lt;code&gt;attrs&lt;/code&gt; 属性的形式保存任意元数据。
名称和属性仅适用于用户和用户编写的代码：xarray 不会尝试解释它们，并且仅在明确的情况下传播它们
（请参阅FAQ，&lt;a href="http://xarray.pydata.org/en/stable/faq.html#approach-to-metadata"&gt;What is your approach to metadata?&lt;/a&gt;）。&lt;/p&gt;
&lt;h3 id="创建-dataarray"&gt;创建 DataArray&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;DataArray&lt;/code&gt; 构造函数需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;data&lt;/code&gt;：数据的多维数组（例如，numpy 的 ndarray，&lt;code&gt;Series&lt;/code&gt;，&lt;code&gt;DataFrame&lt;/code&gt; 或 &lt;code&gt;pandas.Panel&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;coords&lt;/code&gt;：坐标列表或字典。如果是列表，则应为元组列表，其中第一个元素是维度名称，第二个元素是对应的坐标 array_like 对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dims&lt;/code&gt;：维度名称列表。如果省略，并且 &lt;code&gt;coords&lt;/code&gt; 是元组列表，则维度名称取自 &lt;code&gt;coords&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attrs&lt;/code&gt;：添加到对象实例的属性字典&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;：命名对象实例的字符串&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rand(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;locs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;IA&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IL&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;IN&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;times &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date_range(&lt;span style="color:#e6db74"&gt;&amp;#34;2020-01-01&amp;#34;&lt;/span&gt;, periods&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;foo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; coords&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[times, locs],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dims&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;space&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;foo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (time: 4, space: 3)&amp;gt;
array([[0.09558283, 0.54437857, 0.72715542],
 [0.68237872, 0.92443852, 0.04011683],
 [0.77798767, 0.09533936, 0.53837686],
 [0.25279103, 0.46399048, 0.31854009]])
Coordinates:
 * time (time) datetime64[ns] 2020-01-01 2020-01-02 2020-01-03 2020-01-04
 * space (space) &amp;lt;U2 &amp;#39;IA&amp;#39; &amp;#39;IL&amp;#39; &amp;#39;IN&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;只有 &lt;code&gt;data&lt;/code&gt; 是必须指定的；所有其它参数都可以使用默认值。&lt;/p&gt;</description></item><item><title>Bokeh教程：基本绘图</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-06-bokeh-tutorial-basic-plotting/</link><pubDate>Mon, 06 Apr 2020 22:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-06-bokeh-tutorial-basic-plotting/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;bokeh/bokeh-notebooks&lt;/a&gt; 项目，并经过修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本节介绍 &lt;code&gt;bokeh.plotting&lt;/code&gt; 接口。
该接口是“中级”接口，主要思想可以用以下语句描述：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从简单的默认图形（使用默认工具，网格和轴）开始，添加视觉效果直接与数据相关联的标记和其他形状。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们将会看到可以自定义和更改所有默认值，但是拥有默认值意味着可以非常快速地启动并运行。&lt;/p&gt;
&lt;h2 id="导入和设置"&gt;导入和设置&lt;/h2&gt;
&lt;p&gt;当使用 &lt;code&gt;bokeh.plotting&lt;/code&gt; 接口时，有一些常用的导入：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;figure&lt;/code&gt; 函数创建新的绘图对象&lt;/li&gt;
&lt;li&gt;使用函数 &lt;code&gt;output_file&lt;/code&gt; 或 &lt;code&gt;output_notebook&lt;/code&gt;（可以同时使用）告诉 Bokeh 如何显示或保存图像&lt;/li&gt;
&lt;li&gt;执行 &lt;code&gt;show&lt;/code&gt; 或 &lt;code&gt;save&lt;/code&gt; 用于显示或保存绘图和布局&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np &lt;span style="color:#75715e"&gt;# 后面会使用，这里先导入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本示例中，我们使用 Jupyter notebook，所以下面我们调用 &lt;code&gt;output_notebok()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们只需要调用一次，随后所有对 &lt;code&gt;show()&lt;/code&gt; 的调用都会在 notebook 中内联显示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果一切正常，则应该看到 Bokeh 徽标和类似下面的消息作为输出。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;BokehJS 2.0.1 successfully loaded.
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="实战数据"&gt;实战数据&lt;/h3&gt;
&lt;p&gt;使用 &lt;a href="https://github.com/CSSEGISandData/COVID-19"&gt;CSSEGISandData/COVID-19&lt;/a&gt; 项目提供的数据集。&lt;/p&gt;
&lt;p&gt;为了提高加载速度，本示例默认文档已保存到本地的 data 目录中，请从 URL 下载原始文件。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/CSSEGISandData/COVID-19/865c933c0f33f8ccaf4fddc45a13abdbe87036ee/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv"&gt;https://raw.githubusercontent.com/CSSEGISandData/COVID-19/865c933c0f33f8ccaf4fddc45a13abdbe87036ee/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_confirmed &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read_csv(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;data/time_series_covid19_confirmed_global.csv&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_confirmed&lt;span style="color:#f92672"&gt;.&lt;/span&gt;head()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/bokeh/basic-plotting-raw-csv-table.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;原始数据集示例&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;筛选数据，删掉不需要的列，并调整索引。&lt;/p&gt;</description></item><item><title>Bokeh教程：5分钟概览</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-05-bokeh-tutorial-quickstart/</link><pubDate>Sun, 05 Apr 2020 18:15:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-05-bokeh-tutorial-quickstart/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文翻译自 &lt;a href="https://github.com/bokeh/bokeh-notebooks"&gt;https://github.com/bokeh/bokeh-notebooks&lt;/a&gt; 项目。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bokeh 是一个面向现代浏览器的 Python 交互可视化库。
其宗旨是提供 D3.js 风格的优雅、简洁的可视化功能，并将该功能扩展到大型数据集或流式数据集，提供高效的交互能力。
Bokeh 可以为任何想要快速轻松地创建交互式绘图，仪表板和数据应用程序的人提供帮助。&lt;/p&gt;
&lt;h2 id="简单示例"&gt;简单示例&lt;/h2&gt;
&lt;p&gt;下面是第一个示例。
首先，我们将从 &lt;code&gt;bokeh.plotting&lt;/code&gt; 中导入 &lt;code&gt;figure&lt;/code&gt; 函数，这将使我们能轻松地创建各种有趣的图形。
我们还从 &lt;code&gt;bokeh.io&lt;/code&gt; 中导入了 &lt;code&gt;show&lt;/code&gt; 和 &lt;code&gt;ouptut_notebook&lt;/code&gt; 函数，这些函数使我们可以在 notebook 中内联显示结果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.plotting &lt;span style="color:#f92672"&gt;import&lt;/span&gt; figure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; bokeh.io &lt;span style="color:#f92672"&gt;import&lt;/span&gt; output_notebook, show
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来，我们将告诉 Bokeh 将图形直接显示在 notebook 中。
这将导致所有 Javascript 和数据直接嵌入到 notebook 本身的 HTML 中。
Bokeh 可以直接输出为 HTML 文件，也可以使用服务器，稍后我们将介绍。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output_notebook()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出现类似下面的提示，表示 BokehJS 已加载成功。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;BokehJS 2.0.1 successfully loaded.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接下来，我们将导入 NumPy 并创建一些简单数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; numpy &lt;span style="color:#f92672"&gt;import&lt;/span&gt; cos, linspace
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; linspace(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;=&lt;/span&gt; cos(x)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在，我们将调用 Bokeh 的 &lt;code&gt;figure&lt;/code&gt; 函数来创建图 &lt;code&gt;p&lt;/code&gt;。
然后，调用图 &lt;code&gt;p&lt;/code&gt; 的&lt;code&gt;circle()&lt;/code&gt; 方法在 x 和 y 中的每个点上绘制一个红色圆圈。&lt;/p&gt;</description></item><item><title>愿逝者安息</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-04-may-all-the-deceased-rest-in-peace/</link><pubDate>Sat, 04 Apr 2020 20:30:11 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-04-may-all-the-deceased-rest-in-peace/</guid><description>&lt;p&gt;今天是全国哀悼日，悼念抗击新冠肺炎疫情斗争牺牲烈士和逝世同胞，全国下半旗志哀。&lt;/p&gt;
&lt;p&gt;也许只是一个巧合，上午十点，刚好带女儿走到局医院门口，看春天的花，旁边办公楼前有一面国旗。听到防空警报响起，就和女儿一道默哀了三分钟。
尽管女儿坐在婴儿车中，完全不知道实际发生了什么，但我还是希望女儿以后会记住去年底以来为祖国人民做出伟大贡献的医护工作者。&lt;/p&gt;
&lt;p&gt;抗击新冠肺炎战役看似和我没有直接的联系，但类似这样的全国性大事件也许会在不经意间改变人生轨迹。&lt;/p&gt;
&lt;p&gt;上一次参加的全国哀悼活动，还是十二前年的2008年5月19日，全国哀悼四川汶川大地震遇难同胞。
我当时在学校的四大发明广场参加了默哀仪式。
现在看来，虽然仅感受到微弱的震感，但我后续的一系列心路变化却在不知不觉中改变了整个大学的学习生活，而我当时却没有意识到国家大事会在潜移默化中对自己产生影响。&lt;/p&gt;
&lt;p&gt;人生也许有固有的惯性，即使没有特定的事件，也会有一系列其他事件，让生活轨迹最终归结到同一个终点。
但还是不能忽视国家大事对自己的影响。十多年前，我没能看清自身的问题，被自己击倒后艰难地前行。
希望今年我能吸取教训，时刻审视自己，珍惜烈士们为我们创造的大好河山。&lt;/p&gt;
&lt;p&gt;愿逝者安息。&lt;/p&gt;</description></item><item><title>GRIB笔记：获取并加载GRIB 2消息字节流</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-03-grib-notebook-get-raw-bytes-and-load-message-from-them/</link><pubDate>Fri, 03 Apr 2020 21:40:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-03-grib-notebook-get-raw-bytes-and-load-message-from-them/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/04/2020-04-02-grib-notebook-get-field-from-grib2-file/"&gt;GRIB笔记：从GRIB 2文件中加载单个要素场&lt;/a&gt;》介绍如何从本地文件中获取单个要素场。&lt;/p&gt;
&lt;p&gt;如果 GRIB 2 文件保存在远程服务器，想要在本地服务器加载一个要素场，可以将该文件下载到本地，再按照上文介绍的方法读取一个要素场。
这种方式不用修改现有代码，但数据传输量比较大。&lt;/p&gt;
&lt;p&gt;如果在远程服务器从文件中提取要素场，保存为一个临时文件后，本地服务器再下载，就会显著减少数据传输量。
这也是目前单位正在搭建的数据平台使用的方法。&lt;/p&gt;
&lt;p&gt;下面首先介绍如何获取 GRIB 2 消息的原始字节流。&lt;/p&gt;
&lt;h2 id="获取-grib-2-消息字节流"&gt;获取 GRIB 2 消息字节流&lt;/h2&gt;
&lt;p&gt;如果已经从文件中加载 GRIB 2 消息，可以使用 eccodes-python 库提供 &lt;code&gt;eccodes.codes_get_message&lt;/code&gt; 函数返回 GRIB 2 消息的原始字节数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;raw_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get_message(message_id)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式适合手动查找要素场的场景，需要遍历 GRIB 2 文件，找到符合条件的 GRIB 2 消息，每次运行都需要对文件进行解码。&lt;/p&gt;
&lt;p&gt;如果之前已对文件进行一次解码，可以保留每个消息对应的起始字节的偏移量和消息长度，直接从文件加载 GRIB 2 消息。
这也是单位数据平台的核心功能。&lt;/p&gt;
&lt;p&gt;下面的函数仅利用偏移量信息&lt;code&gt;offset&lt;/code&gt;，从文件&lt;code&gt;file_path&lt;/code&gt;中直接加载并返回对应的 GRIB 2 消息。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@attr.s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GribMessageIndex&lt;/span&gt;(object):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; attr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ib()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; attr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ib()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; attr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ib()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;load_bytes_from_index&lt;/span&gt;(index: GribMessageIndex) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; bytes &lt;span style="color:#f92672"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(index&lt;span style="color:#f92672"&gt;.&lt;/span&gt;file_path, &lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;seek(index&lt;span style="color:#f92672"&gt;.&lt;/span&gt;offset)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_grib_new_from_file(f)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; message &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; raw_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get_message(message)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; raw_bytes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果同时使用偏移量和消息长度&lt;code&gt;length&lt;/code&gt;，则可以直接读取文件返回字节流，无需使用 eccodes-python 。&lt;/p&gt;</description></item><item><title>GRIB笔记：从GRIB 2文件中加载单个要素场</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-02-grib-notebook-get-field-from-grib2-file/</link><pubDate>Thu, 02 Apr 2020 22:05:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-02-grib-notebook-get-field-from-grib2-file/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-16-grib-notebook-read-grib-using-cfgrib/"&gt;GRIB笔记：使用cfgrib加载GRIB文件&lt;/a&gt;》介绍如何使用 cfgrib 库读取 GRIB 2 文件。
即使只有一个要素场符合过滤条件，返回的对象仍然是&lt;code&gt;xarray.Dataset&lt;/code&gt;，需要经过一层索引才能得到单个要素场的&lt;code&gt;xarray.DataArray&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用过滤条件从 GRIB 2 文件中获取单个要素场。
示例代码来自&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt;项目。&lt;/p&gt;
&lt;h2 id="过滤条件"&gt;过滤条件&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;nwpc-data&lt;/strong&gt; 项目仅面向 GRAPES 系列模式生成的 GRIB 2 数据，单个文件中只保存同一起报时次同一预报时效的要素场。
所以想要从该文件中检索某个要素场最多需要三个限制条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要素名&lt;/li&gt;
&lt;li&gt;层次类型&lt;/li&gt;
&lt;li&gt;层次值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如检索 850 hPa 温度场需要设置以下三个条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;shortName = &amp;quot;t&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;typeOfLevel = &amp;quot;isobaricInhPa&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;level = 850&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果检索2m温度只需要设置&lt;code&gt;shortName = &amp;quot;2t&amp;quot;&lt;/code&gt;即可。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt;项目设计了一个从本地文件中检索单个要素场的API，返回&lt;code&gt;xarray.DataArray&lt;/code&gt;对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;load_field_from_file&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; file_path: str &lt;span style="color:#f92672"&gt;or&lt;/span&gt; Path,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameter: str &lt;span style="color:#f92672"&gt;or&lt;/span&gt; typing&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Dict,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level_type: str &lt;span style="color:#f92672"&gt;or&lt;/span&gt; typing&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Dict &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level: int &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; engine: str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cfgrib&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt;kwargs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray &lt;span style="color:#f92672"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# ..skip...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该函数通过 &lt;code&gt;engine&lt;/code&gt; 参数支持使用 cfgrib 或 eccodes-python 库加载要素场。&lt;/p&gt;</description></item><item><title>2020年第一季度工作总结</title><link>https://blog.perillaroc.wang/post/2020/04/2020-04-01-2020-q1-summary/</link><pubDate>Wed, 01 Apr 2020 20:20:55 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/04/2020-04-01-2020-q1-summary/</guid><description>&lt;p&gt;没想到2020年的第一个季度如此特殊，只能感叹我还是太年轻了。&lt;/p&gt;
&lt;p&gt;特殊时期也让第一季度的工作显得与之前完全不同。参加工作之后很少单独总结某个季度的工作，最近看到单位不少部门都开了三月或者第一季度工作总结会，过去的三个月刚好可以用来总结一下。
多总结才能吸取经验教训，才能认清当前现状，才能看清前进方向。&lt;/p&gt;
&lt;p&gt;本文从不同的方面介绍我在2020年第一季度做的一些工作，争取在总结的过程中获得我想要的收获。&lt;/p&gt;
&lt;h2 id="业务系统"&gt;业务系统&lt;/h2&gt;
&lt;p&gt;我负责的业务系统建设工作主要集中在业务流程构建和程序集成，几乎不涉及具体的产品程序和绘图脚本开发。&lt;/p&gt;
&lt;p&gt;第一季度负责的业务系统基本没有大型更新，今年的更新任务预计会集中在第二季度。&lt;/p&gt;
&lt;h3 id="增加产品"&gt;增加产品&lt;/h3&gt;
&lt;h4 id="meso-3km-替换-meso-10km-图形产品"&gt;MESO 3km 替换 MESO 10km 图形产品&lt;/h4&gt;
&lt;p&gt;NMC新版网站已于2020年3月正式上线，新版网站上 MESO 10km 的部分图形产品由 MESO 3km 替换。
因为 MESO 3km 的预报时次和预报时效均短于 MESO 10km，所以需要保留 MESO 10km 中 MESO 3km 没有预报数据对应的图片产品。&lt;/p&gt;
&lt;p&gt;为此，我重新设计了 MESO 10km 的图片制作系统，采用遍历算法查找并处理空的容器节点，并将其默认状态设置为 &lt;code&gt;complete&lt;/code&gt;，保证系统可以正常滚动循环。&lt;/p&gt;
&lt;p&gt;详细内容请查看文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-10-ecflow-notebook-deal-with-empty-family/"&gt;ecFlow笔记：处理空的容器节点&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;另外一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-08-nwpc-system-notebook-build-image-production-suite/"&gt;NWPC业务系统笔记：构建图片产品制作系统&lt;/a&gt;》总结了如何使用 ecFlow 构建图形产品制作系统。&lt;/p&gt;
&lt;h4 id="增加冬奥产品"&gt;增加冬奥产品&lt;/h4&gt;
&lt;p&gt;为 GRAPES GFS 和 GRAPES MESO 3km 两个模式增加冬奥数据产品制作任务。&lt;/p&gt;
&lt;h4 id="增加新图片"&gt;增加新图片&lt;/h4&gt;
&lt;p&gt;为 GRAPES TYM 增加雷达反射率图片产品。&lt;/p&gt;
&lt;h3 id="产品更新"&gt;产品更新&lt;/h3&gt;
&lt;p&gt;更新大部分后处理系统的产品库，替换标准底图。&lt;/p&gt;
&lt;p&gt;更新 GRAPES MESO 3km 和 GRAPES MESO 10km 两个区域模式的卫星云图产品，从 FY2G 升级为 FY4A。&lt;/p&gt;</description></item><item><title>从ecCodes的GRIB2消息构建xarray对象</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-31-build-xarray-dataarray-from-eccodes-message/</link><pubDate>Tue, 31 Mar 2020 22:15:26 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-31-build-xarray-dataarray-from-eccodes-message/</guid><description>&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-16-grib-notebook-read-grib-using-cfgrib/"&gt;GRIB笔记：使用cfgrib加载GRIB文件&lt;/a&gt;》中介绍使用 cfgrib 将 GRIB 消息加载为&lt;code&gt;xarray.DataArray&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;经过最近一段时间的几次测试，发现 cfgrib 从 GRAPES GFS 的原始分辨率 GRIB 文件中检索并加载单个要素场需要4-5秒左右，远远超过直接使用 eccodes-python 的时间。
初步使用Dask并行加载要素场时，感觉加载时间被进一步延长，严重制约数据计算的速度。&lt;/p&gt;
&lt;p&gt;我还没有仔细研究 cfgrib 的源码，不知道是我使用方法不正确，还是 cfgrib 本身速度比较慢。
不过，有一种折中的方案，使用 eccodes-python 查找并加载 GRIB 2 要素场，将其仿照 cfgrib 包装成 &lt;code&gt;xarray.DataArray&lt;/code&gt; 对象。&lt;/p&gt;
&lt;p&gt;本文介绍一种简单的封装方法。&lt;/p&gt;
&lt;h2 id="查找要素场"&gt;查找要素场&lt;/h2&gt;
&lt;p&gt;GRAPES GFS 的原始分辨率 GRIB 2 数据每个文件只包含一个时次的一个时效，所以查找要素场只需要指定要素名、层次类型和层次。&lt;/p&gt;
&lt;p&gt;如果要素场有 &lt;code&gt;shortName&lt;/code&gt;，则只需要从 GRIB 2 消息中读取 &lt;code&gt;shortName&lt;/code&gt;, &lt;code&gt;typeOfLevel&lt;/code&gt; 和 &lt;code&gt;level&lt;/code&gt; 并比较与给定的筛选条件是否相等。&lt;/p&gt;
&lt;p&gt;如果要素场没有 &lt;code&gt;shortName&lt;/code&gt;，则可以通过 &lt;code&gt;discipline&lt;/code&gt;, &lt;code&gt;parameterCategory&lt;/code&gt; 和 &lt;code&gt;parameterNumber&lt;/code&gt; 确定要素，再比较 &lt;code&gt;typeOfLevel&lt;/code&gt; 和 &lt;code&gt;level&lt;/code&gt; 即可。&lt;/p&gt;
&lt;p&gt;具体代码请访问 &lt;a href="https://github.com/nwpc-oper/nwpc-data"&gt;nwpc-oper/nwpc-data&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h2 id="构建二维数组"&gt;构建二维数组&lt;/h2&gt;
&lt;p&gt;查找到要素场后，返回的是 GRIB 2 消息的 handler。
使用 eccodes-python 的 API 可以从 handler 中获取 GRIB 2 消息的数据段和属性。&lt;/p&gt;</description></item><item><title>视界：释放机器数据的隐藏价值以改善ECMWF的服务</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-29-view-unlocking-hidden-value-machine-data-improve-ecmwfs-services/</link><pubDate>Sun, 29 Mar 2020 21:15:57 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-29-view-unlocking-hidden-value-machine-data-improve-ecmwfs-services/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自 ECMWF Newsletter Number 162 - Winter 2020 中的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/162/computing/unlocking-hidden-value-machine-data-improve-ecmwfs-services"&gt;Unlocking the hidden value of machine data to improve ECMWF’s services&lt;/a&gt;》，版权归ECMWF所有。翻译底稿来自Google翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;“没有数据，您只是另一个有意见的人而已。” 这种说法通常归因于已故的美国工程师和统计学家W. Edwards Deming，无疑在许多情况下都是有效的。在本文中，作者阐述了ECMWF生成的机器数据如何能提供对提高中心服务有价值的见解。&lt;/p&gt;
&lt;h3 id="什么是机器数据"&gt;什么是机器数据&lt;/h3&gt;
&lt;p&gt;机器数据（Machine data）是由计算机，网站，安全系统，网络，智能手机，智能汽车等的活动生成的日志。它们未被充分利用，但由于包含重要的隐藏信息而非常有价值。它们可能有用的领域包括：监视和故障排除，根本原因分析，性能分析，安全性，业务分析，市场洞察力，用户行为和客户支持。&lt;/p&gt;
&lt;p&gt;机器数据是增长最快的大数据之一。关系数据库和传统方法/软件无法非常有效地管理这些大量数据。因此，出现了专门为机器日志设计的更复杂的技术，使组织能够从以前无法访问或未使用的数据中获得新的见解。此外，将人工智能和机器学习技术应用于机器日志分析可以帮助公司实现某些流程的自动化，并使业务运维的工作方式从响应式转变为预测式。&lt;/p&gt;
&lt;p&gt;在 ECMWF，产生大量机器数据的主要系统之一是 MARS，即中心的气象档案和检索系统（Meteorological Archival and Retrieval System）。MARS 使用户可以访问 ECMWF 的气象数据，例如业务预报，气象观测，再分析和许多公共数据集。用户可以从 ECMWF 的任何计算机访问该归档存储，也可以通过基于 Web 的 API 接口（Web-API）远程访问。在典型的一天中，MARS 处理 150 万个用户请求并提供 400 TB 的数据。&lt;/p&gt;
&lt;h3 id="分析数据"&gt;分析数据&lt;/h3&gt;
&lt;p&gt;MARS 和 Web-API 每天生成大量的多结构日志，分布在多个系统上。在一个通用平台上收集和存储这些各种各样的数据将使我们能够更有效地分析日志并获得对整个服务的新见解。&lt;/p&gt;
&lt;p&gt;两年前，我们决定基于 Splunk（一种用于提取，搜索，监视和分析机器日志的日志管理平台）进行概念验证项目 (proof‐of‐concept)。Splunk 自2015年以来已在 ECMWF 使用，可用于生成交互式工具，报告，警报，可视化等。最初，我们致力于处理历史数据以生成相关的报告和统计信息（图1）。然后，我们开始通过分析近实时日志来应对更多的日常运营挑战（图2）。从那时起，我们将 Splunk 的使用范围扩展到了更广泛的日志集，并且我们已自动记录了各种活动。下面介绍了一些收益和用例。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2020-01/NL162-C2-Manoussakis-Fig-1_sized-for-Boream.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;图1 使用机器数据在自定义仪表板中创建了这些图表，以显示2014年至2018年ECMWF Web-API活动的不同方面。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2020-01/NL162-C2-Manoussakis-Fig-2_sized-for-Boream.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;图2：根据前四个小时内 Apache 服务器日志的近实时 Web-API 用户活动，按公共数据集和位置分类。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="运行监控和故障排除"&gt;运行监控和故障排除&lt;/h3&gt;
&lt;p&gt;速度在业务服务中至关重要。通过从多个系统近实时地收集，提取和处理实时日志流，我们可以发现问题，及早发出警报，立即采取行动并更主动地监控业务服务的运行状况。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：添加自定义表格</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-28-grib-notebook-add-local-table/</link><pubDate>Sat, 28 Mar 2020 22:25:07 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-28-grib-notebook-add-local-table/</guid><description>&lt;p&gt;使用 ecCodes 查看 GRAPES GFS 模式的 GRIB 2 文件，有很多变量无法自动识别。&lt;/p&gt;
&lt;p&gt;例如下面&lt;code&gt;grib_ls&lt;/code&gt;命令输出中，无法识别&lt;code&gt;shortName&lt;/code&gt;的变量用&lt;code&gt;unknown&lt;/code&gt;表示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;805 2 babj 20200328 fc regular_ll isobaricInhPa 950 3 unknown grid_jpeg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;806 2 babj 20200328 fc regular_ll isobaricInhPa 925 3 unknown grid_jpeg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面&lt;code&gt;grib_dump&lt;/code&gt;命令输出中可以看到，表格&lt;code&gt;grib2/tables/4/4.2.0.2.table&lt;/code&gt;中没有225的条目，该值属于自定义字段。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_4 ( length=34, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section4Length = 34
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-7 NV = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8-9 productDefinitionTemplateNumber = 0 [Analysis or forecast at a horizontal level or in a horizontal layer at a point in time (grib2/tables/4/4.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10 parameterCategory = 2 [Momentum (grib2/tables/4/4.1.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 parameterNumber = 225 [Unknown code table entry (grib2/tables/4/4.2.0.2.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文介绍如何添加自定义表格，让 ecCodes 可以自动识别自定义的变量。&lt;/p&gt;</description></item><item><title>统计数值天气预报模式产品生成时间</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-27-analytic-nwp-model-production-time/</link><pubDate>Fri, 27 Mar 2020 15:25:41 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-27-analytic-nwp-model-production-time/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-25-analytic-nwp-model-running-time/"&gt;统计数值天气预报模式积分运行时间&lt;/a&gt;》比较不同日期中模式积分的运行时间，本文则对比逐时效产品的生成时间。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，用于说明NWPC消息分析工具的应用场景，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="统计方法"&gt;统计方法&lt;/h2&gt;
&lt;p&gt;统计每个时效的GRIB2数据完成上传二级存储的时间。&lt;/p&gt;
&lt;p&gt;时间数据来自向NWPC消息平台发送的产品消息，类似之前文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-23-nwpc-production-message-for-nmc-monitor/"&gt;适用于NMC监控平台的数值预报产品消息&lt;/a&gt;》中介绍的消息。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;nwpc-message-client&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2020-03-26T04:32:52.154795231Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;system&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;model_D&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;stream&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;oper&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;grib2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;orig&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;start_time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2020-03-26T00:00:00Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;forecast_time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;000h&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;storage&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="统计工具"&gt;统计工具&lt;/h2&gt;
&lt;p&gt;产品消息发送和存储使用&lt;a href="https://github.com/nwpc-oper/nwpc-message-client"&gt;nwpc-oper/nwpc-message-client&lt;/a&gt;。消息数据保存到ElasticSearch中。&lt;/p&gt;
&lt;p&gt;数据汇总和可视化使用&lt;a href="https://github.com/nwpc-oper/nwpc-message-tool"&gt;nwpc-oper/nwpc-message-tool&lt;/a&gt;。
使用Bokeh实现可视化。&lt;/p&gt;
&lt;h2 id="统计数据"&gt;统计数据&lt;/h2&gt;
&lt;p&gt;统计以下模式2020年3月19日至3月25日00时次的产品生成情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Model A&lt;/li&gt;
&lt;li&gt;Model B&lt;/li&gt;
&lt;li&gt;Model C&lt;/li&gt;
&lt;li&gt;Model D&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="统计结果"&gt;统计结果&lt;/h2&gt;
&lt;h3 id="model-a"&gt;Model A&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-A-bar.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model A的产品生成时间段&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-A-grid.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model A的产品逐时效生成时间网格图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="model-b"&gt;Model B&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-B-bar.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model B的产品生成时间段&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-B-grid.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model B的产品逐时效生成时间网格图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="model-c"&gt;Model C&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-C-bar.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model C的产品生成时间段&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-C-grid.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model C的产品逐时效生成时间网格图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="model-d"&gt;Model D&lt;/h3&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-D-bar.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model D的产品生成时间段&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/model-D-grid.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model D的产品逐时效生成时间网格图&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="结果分析"&gt;结果分析&lt;/h2&gt;
&lt;p&gt;除了两次特殊情况外，最后一个产品的生成时间相差在10分钟左右。&lt;/p&gt;</description></item><item><title>统计数值天气预报模式积分运行时间</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-25-analytic-nwp-model-running-time/</link><pubDate>Wed, 25 Mar 2020 17:28:38 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-25-analytic-nwp-model-running-time/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍NWPC工作流日志分析的系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最近一段时间，单位对数值预报业务系统产品的时效性越来越重视。
之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-23-nwpc-production-message-for-nmc-monitor/"&gt;适用于NMC监控平台的数值预报产品消息&lt;/a&gt;》中介绍气象中心建立统一监控平台，展示包括数值预报在内的各个业务产品的到达时间。另外，气象中心每天还在微信公众号“中央气象台运维平台”上推送“每日运维快报”，通报所有产品是否准时到达。
产品延迟超过30分钟注定会被正式当做故障指标。
另外，今年即将到来的版本更新可能会增加模式积分的运行时间，留给产品制作和故障处理的窗口时间会越来越少，运维面临严峻的挑战。&lt;/p&gt;
&lt;p&gt;作为一线运维人员，我们一直怀疑产品延迟与模式积分时长的不稳定有关系，本文试图通过统计数据来判断这一猜测是否有实际依据。&lt;/p&gt;
&lt;p&gt;本文利用ecFlow日志，统计业务系统中四个模式积分任务的运行时间。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明&lt;/strong&gt;：本文仅代表作者个人观点，用于说明NWPC工作流日志分析工具的应用场景，所用数据无法代表真实情况，严禁转载。关于模式系统的相关信息，请以官方发布的信息及经过同行评议的论文为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="统计方法"&gt;统计方法&lt;/h2&gt;
&lt;p&gt;根据ecFlow的运行日志计算每个时次模式积分任务的开始和结束时间。
下面是某个模式积分任务某次运行的ecFlow日志示例，其中&lt;code&gt;submiited&lt;/code&gt;表示任务开始，&lt;code&gt;complete&lt;/code&gt;表示任务结束。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOG:[04:19:46 3.1.2020] submitted: /model_A/00/model/fcst_long job_size:18261
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOG:[04:19:54 3.1.2020] active: /model_A/00/model/fcst_long
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LOG:[04:45:13 3.1.2020] complete: /model_A/00/model/fcst_long
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了得到稳定可信的参考值，将开始时间和结束时间的切尾均值作为标准时间，使用比率0.25计算切尾均值。&lt;/p&gt;
&lt;p&gt;最后计算实际结束时间与标准结束时间的差值，标记超过30分钟的时次。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：从ecFlow日志得到的时间只是对实际运行时间的近似估计，不是模式积分程序的精确运行时间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="统计工具"&gt;统计工具&lt;/h2&gt;
&lt;p&gt;日志分析和统计计算使用 &lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-tool"&gt;nwpc-oper/nwpc-workflow-log-tool&lt;/a&gt; 项目提供的工具。&lt;/p&gt;
&lt;p&gt;使用 Excel 进行辅助计算。&lt;/p&gt;
&lt;p&gt;图表由 Google 表格制作。&lt;/p&gt;
&lt;h2 id="统计数据"&gt;统计数据&lt;/h2&gt;
&lt;p&gt;统计以下模式在2020年2月23日至3月23日共30天00时次的运行时间：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MODEL A&lt;/li&gt;
&lt;li&gt;MODEL B&lt;/li&gt;
&lt;li&gt;MODEL C&lt;/li&gt;
&lt;li&gt;MODEL D&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后续数据中时间均为UTC时间。&lt;/p&gt;
&lt;h2 id="统计结果"&gt;统计结果&lt;/h2&gt;
&lt;p&gt;简要说明各个模式的统计结果。&lt;/p&gt;
&lt;h3 id="model-a"&gt;MODEL A&lt;/h3&gt;
&lt;p&gt;标准结束时间：04:43:55。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/Model%20forecast%20running%20length%20for%20Model%20A.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model A的模式积分运行时长，紫色标记表示结束时间超过标准时间30分钟&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/Model%20forecast%20start%20and%20end%20time%20clock%20for%20Model%20A.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model A的模式积分任务起止时间&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="model-b"&gt;MODEL B&lt;/h3&gt;
&lt;p&gt;标准结束时间：05:36:19。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/Model%20forecast%20running%20length%20for%20Model%20B.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model B的模式积分运行时长&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/Model%20forecast%20start%20and%20end%20time%20clock%20for%20Model%20B.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Model B的模式积分任务起止时间&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="model-c"&gt;MODEL C&lt;/h3&gt;
&lt;p&gt;标准结束时间：04:00:03。&lt;/p&gt;</description></item><item><title>动态解析命令行参数</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-24-dynamic-cli-option-parsing/</link><pubDate>Tue, 24 Mar 2020 11:55:55 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-24-dynamic-cli-option-parsing/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-23-nwpc-production-message-for-nmc-monitor/"&gt;适用于NMC监控平台的数值预报产品消息&lt;/a&gt;》中提到数值预报中心的数值预报业务系统使用命令行客户端向消息平台发送消息。
虽然目前只发送确定性预报模式的GRIB2产品消息，但需要考虑后续如何进行扩展。&lt;/p&gt;
&lt;p&gt;不同消息需要传递的参数不完全一样，可以为每种消息单独开发命令行接口。例如&lt;a href="https://github.com/nwpc-oper/nwpc-message-client"&gt;nwpc-oper/nwpc-message-client&lt;/a&gt;为产品消息和ecflow_client命令单独开发两个子命令。&lt;/p&gt;
&lt;p&gt;不过，产品消息也可能有多个不同的类型，例如上面文章中提到集合预报模式的产品比确定性模式多一个表示集合成员的字段。
为每个的消息类型都各自开发一个命令行接口会显著增加系统的复杂性。而将所有可能的参数都添加到同一个命令中会导致命令行接口过于复杂。&lt;/p&gt;
&lt;p&gt;一个可行的办法是开发一个命令行接口，针对不同的消息类型，使用不同的命令行参数。&lt;/p&gt;
&lt;p&gt;目前业务系统使用的消息发送命令行程序都是用GOLANG实现，使用Cobra库开发命令行接口。
本文介绍如何在Cobra基础上通过设置消息类型等参数，实现动态解析命令行参数。&lt;/p&gt;
&lt;h2 id="命令行参数解析"&gt;命令行参数解析&lt;/h2&gt;
&lt;p&gt;在之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/02/2020-02-22-use-cobra-to-create-cli-program/"&gt;使用Cobra构建命令行程序&lt;/a&gt;》中介绍如何使用Cobra创建命令行程序。&lt;/p&gt;
&lt;p&gt;下面代码截取自&lt;a href="https://github.com/nwpc-oper/nwpc-message-client"&gt;nwpc-oper/nwpc-message-client&lt;/a&gt;项目，使用Cobra默认的方式构建命令行参数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;brokerCmd&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cobra&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Command&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Use&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;broker&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Short&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;A broker for NWPC Message Client&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Long&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;brokerDescription&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;RunE&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;bc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;runCommand&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;brokerCmd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Flags&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;StringVar&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;brokerAddress&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;address&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;:33383&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;broker rpc address, use tcp port.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;brokerCmd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Flags&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;BoolVar&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;disableDeliver&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;disable-deliver&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;disable deliver messages to message queue, just for debug.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述方法必须在进行参数解析前就设置好参数选项，无法动态设置参数。&lt;/p&gt;
&lt;p&gt;不过&lt;code&gt;cobra.Command&lt;/code&gt;提供&lt;code&gt;DisableFlagParsing&lt;/code&gt;选项可以关闭内置的参数解析，用户可以手动编写命令行解析程序。&lt;/p&gt;
&lt;p&gt;下面介绍如何使用pflag库实现动态参数解析。&lt;/p&gt;
&lt;h2 id="动态解析参数"&gt;动态解析参数&lt;/h2&gt;
&lt;p&gt;创建&lt;code&gt;pflag.NewFlagSet&lt;/code&gt;，配置一组命令行参数信息，用于解析通用的参数。&lt;/p&gt;
&lt;p&gt;因为没有包含诸如&lt;code&gt;--start-time&lt;/code&gt;等与消息类型相关的参数，直接调用&lt;code&gt;Parse()&lt;/code&gt;会因为无法识别某些参数而出错。
需要设置&lt;code&gt;ParseErrorsWhitelist&lt;/code&gt;，忽略无法识别的参数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;pflag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewFlagSet&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;send&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;pflag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ContinueOnError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ParseErrorsWhitelist&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;pflag&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ParseErrorsWhitelist&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;UnknownFlags&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;SortFlags&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StringVar&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;message source&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StringVar&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;messageType&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;message type&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ...skip...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;BoolVar&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;help&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;help&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;show help information.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sendFlagSet&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Parse&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;); &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cmd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Usage&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fatal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于GRIB2消息，可以创建另一个&lt;code&gt;pflag.NewFlagSet&lt;/code&gt;，单独解析。&lt;/p&gt;</description></item><item><title>使用Bulk API向ElasticSearch发送数据</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-19-send-messages-into-elasticsearch-using-bulk-api/</link><pubDate>Thu, 19 Mar 2020 21:00:05 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-19-send-messages-into-elasticsearch-using-bulk-api/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章的第一篇文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-message-client"&gt;nwpc-oper/nwpc-message-client&lt;/a&gt;
和
&lt;a href="https://github.com/nwpc-oper/nmc-message-client"&gt;nwpc-oper/nmc-message-client&lt;/a&gt;
两个项目用于向消息队列发送产品生成消息，已应用在数值预报中心的 GRAPES 确定性模式系统中。
项目中包括用于消息持久化的命令行工具，从消息队列接收消息并保存到 ElasticSearch 中。&lt;/p&gt;
&lt;p&gt;逐条向 ElasticSearch 发送数据效率太低，本文介绍如何使用 Bulk API 批量发送数据。&lt;/p&gt;
&lt;h2 id="策略"&gt;策略&lt;/h2&gt;
&lt;p&gt;发送数据既要考虑采用批量发送减少请求次数，也要考虑到消息的时效性。
所以采用如下策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;接收消息，保存到 &lt;em&gt;暂存数组&lt;/em&gt; 中。&lt;/li&gt;
&lt;li&gt;如果消息数目超过 &lt;em&gt;发送阈值&lt;/em&gt;，发送消息。&lt;/li&gt;
&lt;li&gt;等待超过一定 &lt;em&gt;时间阈值&lt;/em&gt;，将暂存数组中的消息全部发送。&lt;/li&gt;
&lt;li&gt;如果发送失败，保留暂存数组数据。&lt;/li&gt;
&lt;li&gt;如果暂存数组大小超过 &lt;em&gt;发送阈值&lt;/em&gt; 的一定倍数，程序直接退出。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面介绍 &lt;a href="https://github.com/nwpc-oper/nmc-message-client"&gt;nwpc-oper/nmc-message-client&lt;/a&gt; 如何应用上述策略。&lt;/p&gt;
&lt;h2 id="应用"&gt;应用&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nmc-message-client&lt;/code&gt; 使用 GOLONG 实现命令行程序，从 Kafka 服务器接收消息，并保存到 ElasticSearch 中。&lt;/p&gt;
&lt;p&gt;下图是该工具核心流程的示意图。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/message/message-consumer.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;利用 Golang 的通道实现定时批量发送数据&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;工具在一个 Goroutine (Reader Goroutine) 中从 Kafka 队列读取消息，并将消息发送到消息通道 (message channel) 中。&lt;/p&gt;
&lt;p&gt;主 Goroutine (Main Goroutine) 的核心是一个无限循环，循环中使用 &lt;code&gt;select&lt;/code&gt; 语句等待两个事件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;receive：从 message channel 中接收一个消息&lt;/li&gt;
&lt;li&gt;timeout：等待超过一定的时间阈值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接收消息后，会将消息保存到暂存数组 (Message Bag)。
如果缓存数量超过发送阈值 (bulk size)，会将全部缓存数据发送到 ElasticSearch 中。
发送成功后，会清空暂存数组。发送失败，则直接进入下一次循环。&lt;/p&gt;</description></item><item><title>使用Python生成器封装ElasticSearch查询结果</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-17-use-generator-to-return-query-results-from-elasticsearch/</link><pubDate>Tue, 17 Mar 2020 22:50:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-17-use-generator-to-return-query-results-from-elasticsearch/</guid><description>&lt;p&gt;Elasticsearch 默认查询返回 10 个结果，可以通过设置 &lt;code&gt;size&lt;/code&gt; 和 &lt;code&gt;from&lt;/code&gt; 获取更多的查询结果。
如果 &lt;code&gt;size&lt;/code&gt; 设置过大，会显著增加查询执行时间。所以推荐通过多次查询获取全部符合条件的文档。&lt;/p&gt;
&lt;p&gt;本文介绍如何将 Elasticsearch 的查询结果封装到 Python 生成器中，返回所有的查询结果。&lt;/p&gt;
&lt;h2 id="查询"&gt;查询&lt;/h2&gt;
&lt;p&gt;本文使用 &lt;a href="https://github.com/elastic/elasticsearch-py"&gt;elasticsearch-py&lt;/a&gt; 库访问 Elasticsearch 库。&lt;/p&gt;
&lt;p&gt;创建一个客户端。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Elasticsearch(hosts&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;localhost:9200&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构建查询体，从第一条记录开始返回20条记录。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;search_body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;size&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;from&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bool&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;must&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;data.system&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;grapes_meso_3km&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;data.start_time&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2020-03-17T00:00:00&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行查询操作，将查询结果解析为 &lt;code&gt;message&lt;/code&gt; 对象，放到数组中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;search(index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;2020-03&amp;#34;&lt;/span&gt;, body&lt;span style="color:#f92672"&gt;=&lt;/span&gt;search_body)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;messages &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; hit &lt;span style="color:#f92672"&gt;in&lt;/span&gt; res[&lt;span style="color:#e6db74"&gt;&amp;#39;hits&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;hits&amp;#39;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; messages&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(load_message(hit[&lt;span style="color:#e6db74"&gt;&amp;#34;_source&amp;#34;&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="返回所有数据"&gt;返回所有数据&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;res['hits']['total']['value']&lt;/code&gt; 是符合条件的文档数量，获取所有数据可以递增 &lt;code&gt;search_body&lt;/code&gt; 的 &lt;code&gt;from&lt;/code&gt; 值，重复执行查询操作。&lt;/p&gt;</description></item><item><title>xarray基本用法</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-15-xarray-quick-overview/</link><pubDate>Sat, 14 Mar 2020 21:28:34 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-15-xarray-quick-overview/</guid><description>&lt;p&gt;本文介绍xarray的基本用法，来自官方文档。&lt;/p&gt;
&lt;p&gt;下面是一些简单的示例，介绍如何使用&lt;code&gt;xarray.DataArray&lt;/code&gt;对象。
示例中介绍的所有用法都会在官方文档中有更详细的解释。&lt;/p&gt;
&lt;p&gt;开始之前，请使用惯用缩写加载 numpy，pandas 和 xarray 库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pandas &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; pd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; xarray &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; xr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="创建dataarray"&gt;创建DataArray&lt;/h2&gt;
&lt;p&gt;从numpy数组或list中创建DataArray，附加可选的&lt;code&gt;dimensions&lt;/code&gt;和&lt;code&gt;coordinates&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;random&lt;span style="color:#f92672"&gt;.&lt;/span&gt;randn(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dims&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;y&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; coords&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;]}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (x: 2, y: 3)&amp;gt;
array([[ 0.72416562, -0.91294078, -0.76305295],
 [ 0.26180493, -0.5472152 , -1.12753176]])
Coordinates:
 * x (x) int32 10 20
Dimensions without coordinates: y
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上面代码创建一个二维数组，将两个维度命名为&lt;code&gt;x&lt;/code&gt;和&lt;code&gt;y&lt;/code&gt;，并将两个坐标标签&lt;code&gt;10&lt;/code&gt;和&lt;code&gt;20&lt;/code&gt;赋值给x维度对应的两个位置。&lt;/p&gt;
&lt;p&gt;如果向DataArray提供pandas的&lt;code&gt;Series&lt;/code&gt;和&lt;code&gt;DataFrame&lt;/code&gt;，会自动拷贝元数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_covid &lt;span style="color:#f92672"&gt;=&lt;/span&gt; xr&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataArray(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pd&lt;span style="color:#f92672"&gt;.&lt;/span&gt;DataFrame(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;confirmed&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;437&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;350&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;136&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;576&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;recovered&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;349&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;324&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;132&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;566&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;active&amp;#34;&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; index&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;beijing&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;shanghai&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;tianjin&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;chongqing&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dims&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;city&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;cases&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;data_covid
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;lt;xarray.DataArray (city: 4, cases: 3)&amp;gt;
array([[437, 349, 80],
 [350, 324, 24],
 [136, 132, 1],
 [576, 566, 4]], dtype=int64)
Coordinates:
 * city (city) object &amp;#39;beijing&amp;#39; &amp;#39;shanghai&amp;#39; &amp;#39;tianjin&amp;#39; &amp;#39;chongqing&amp;#39;
 * cases (cases) object &amp;#39;confirmed&amp;#39; &amp;#39;recovered&amp;#39; &amp;#39;active&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下面代码展示&lt;code&gt;DataArray&lt;/code&gt;的关键属性。&lt;/p&gt;</description></item><item><title>要有做事情的魄力和专注</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-13-be-focused-and-courageous-in-doing-things/</link><pubDate>Fri, 13 Mar 2020 18:58:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-13-be-focused-and-courageous-in-doing-things/</guid><description>&lt;p&gt;当我们在一个领域中工作足够长时间后，总能看到一些当前的不足与前进的方向。
区别在于是否有魄力做出改变，是否有信心去坚持改变。&lt;/p&gt;
&lt;h2 id="面临的挑战"&gt;面临的挑战&lt;/h2&gt;
&lt;p&gt;最近看到国家气象信息中心同事的《ECMWF访问工作总结》，深有感触。&lt;/p&gt;
&lt;p&gt;同事原计划主要研究模式支撑系统，并学习HPC在业务支撑和精细化资源管理和调度方面的工作，即信息中心高性能计算室主要从事的工作。
但因为某些原因调到负责业务系统集成、构建、运行维护的部门，也就是数值预报中心系统业务室的工作。&lt;/p&gt;
&lt;p&gt;同事在一年的访问交流中&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;负责将数据分析平台SPLUCK应用到ECMWF现有的实时数值预报业务中，
通过对数值预报业务运行状态的抓取，对业务模式的运行数据进行挖掘，分析业务历史和实时运行状态，
实现对业务运行故障的报警和预警，特别针对模式运行关键模块延迟等异常情况，
最终可为用户提预测供预报产品可获取的时间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;第一阶段工作主要是熟悉Splunk，并分析Web访问日志。
因为我们部门不提供Web服务，所以这部分工作我几乎没有涉及。&lt;/p&gt;
&lt;p&gt;第二阶段的工作才是我关注的重点，工作目标包括：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;实现近实时的对业务模式运行状态的可视化展示并可以按需求对历史运行状态进行分析；&lt;/li&gt;
&lt;li&gt;从简单的文本信息中挖掘有价值的模型帮助他们更好的了解业务模式运行的状态，改善模式流程并协助模式流程开发过程中的测试工作；&lt;/li&gt;
&lt;li&gt;实现对业务模式特别是关键模块的实时监控，对于异常情况给出预警和报警以及异常的定位和详细信息；&lt;/li&gt;
&lt;li&gt;预测模式预报产品的生产时间，如果产生延迟，可以预估产品可能的交付时间。&lt;/li&gt;
&lt;li&gt;开发的相关Dashboards和分析结果将应用在ECMWF新数据中心的业务运行监控和展示以及他们业务运行报告和KPI评估中。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;上面的工作目标与数值预报业务系统运行维护息息相关，都是我们科室正在做或者想要做的事情。&lt;/p&gt;
&lt;p&gt;无论是国际领先的ECMWF，还是信息化水平较低的我们，大家面临的挑战都是一样的。
但区别就在于，看到问题后是否有魄力去解决，是否有毅力去坚持解决。
很遗憾，我在这方面尚有欠缺。&lt;/p&gt;
&lt;h2 id="工作对比"&gt;工作对比&lt;/h2&gt;
&lt;p&gt;上面的工作可以分为以下几点。&lt;/p&gt;
&lt;h3 id="历史运行状态分析"&gt;历史运行状态分析&lt;/h3&gt;
&lt;p&gt;从后文的介绍推测历史运行状态分析可能使用归档的ecFlow日志。&lt;/p&gt;
&lt;p&gt;我在2015-2016年度国家气象中心青年基金课题《数值预报业务系统运行状态分析》中有过类似的研究。
相关成果可以参考2017年在第34届中国气象学会年会
“S20 气象数据：深度应用和标准化”分会场汇报的《&lt;a href="http://cpfd.cnki.com.cn/Article/CPFDTOTAL-ZGQX201709020023.htm"&gt;基于SMS的数值预报运行日志分析系统&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;遗憾的是我当时没有选用成熟的数据可视化工具（例如ECMWF使用的Splunk），而是自己用AngularJS编写简易的网站。
我并没有专注JavaScript编程，导致该项目的可视化网站后续没有更新。&lt;/p&gt;
&lt;p&gt;另外，我们的业务系统直到现在也没有对SMS或ecFlow的日志进行定期归档，该项目收集日志的方法过于繁琐，实时运行一段时间后就放弃了。&lt;/p&gt;
&lt;p&gt;但该项目的数据处理和分析方法已被我继承到目前还在开发维护的项目中。&lt;/p&gt;
&lt;p&gt;为了展示业务系统全天的运行状态，我开发了业务系统运行时间线，如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/systems-time-line.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;2019年7月22日数值预报业务系统运行时间线&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;开发的项目包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-tool"&gt;nwpc-oper/nwpc-workflow-log-tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-model"&gt;nwpc-oper/nwpc-workflow-log-model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-workflow-log-processor"&gt;nwpc-oper/nwpc-workflow-log-processor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/perillaroc/nuwe-timeline"&gt;perillaroc/nuwe-timeline&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前三个项目正处于重构当中，希望今年我能提供一套方便使用的工具。&lt;/p&gt;
&lt;h3 id="实时状态监控"&gt;实时状态监控&lt;/h3&gt;
&lt;p&gt;近实时的业务模式运行状态展示，对于异常情况给出预警和报警，这两项工作我已开展研究，成果已应用在业务系统中。
相关论文《&lt;a href="http://www.qxkj.net.cn/qxkj/article/abstract/20180508"&gt;数值预报业务系统移动监控平台的设计与实现&lt;/a&gt;》已发表在《气象科技》2018年第5期。&lt;/p&gt;
&lt;p&gt;开发的项目包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nmp-model"&gt;nwpc-oper/nmp-model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nmp-broker"&gt;nwpc-oper/nmp-broker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nmp-scheduler"&gt;nwpc-oper/nmp-scheduler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/nmp-web"&gt;nwpc-oper/nmp-web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwpc-oper/ecflow-client-cpp"&gt;nwpc-oper/ecflow-client-cpp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于异常的定位和详细信息，我们正在借助工程项目进行开发，今年会有一些初步的成果。&lt;/p&gt;
&lt;h3 id="产品生成时间预测"&gt;产品生成时间预测&lt;/h3&gt;
&lt;p&gt;产品的时效性一直不是我们关注的重点，我们更多关注产品是否生成。
不过最近中央气象台专门申请了运维的公众号，会通报各种资料的到达情况，其中包括我们负责维护的三个模式。
所以通过历史数据分析产品生成时间，乃至更进一步通过当前状态预测产品生成时间都应该成为我们研究的方向。&lt;/p&gt;
&lt;p&gt;时间序列预测是一个很有意思的课题，今年争取找时间能了解一下。&lt;/p&gt;
&lt;h3 id="程序日志挖掘"&gt;程序日志挖掘&lt;/h3&gt;
&lt;p&gt;虽然我们存储了所有程序的运行日志，但还没有对日志进行过分析。
在这一方面上，我们明显落后于行业和时代。
今年会尝试进行简单的数据分析，看看能否对业务运行维护提供支持。&lt;/p&gt;
&lt;h3 id="可视化展示"&gt;可视化展示&lt;/h3&gt;
&lt;p&gt;在可视化Dashboard展示方面，我们还欠缺很多。
我们没有要求统一使用 Splunk 类似的工具，所以我做大部分工具都是自己搭建简易的web页面来进行数据展示，浪费精力，效果也不好。&lt;/p&gt;
&lt;p&gt;唯一涉及 Dashboad 的项目就是使用 Grafana 显示 Prometheus 中保存的HPC监控数据，如下图所示：&lt;/p&gt;</description></item><item><title>CMA-PI上共享存储访问工具cmafs介绍</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-11-implementation-of-storage-tool-named-cmafs/</link><pubDate>Wed, 11 Mar 2020 17:57:38 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-11-implementation-of-storage-tool-named-cmafs/</guid><description>&lt;blockquote&gt;
&lt;p&gt;2020.04.16 注：最新版的 cmafs 已经使用当前用户免密码登陆二级存储挂载节点，也就意味着放开了普通用户对挂载节点的访问权限。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如何存储和获取历史数据一直是数值预报模式研发人员关心的问题。&lt;/p&gt;
&lt;p&gt;ECMWF有完善的数据归档系统（MARS），提供丰富的接口支持检索和下载归档的模式数据。
但我们还缺乏类似的平台，历史数据大多以离线硬盘的形式保存。&lt;/p&gt;
&lt;p&gt;中国气象局正在建设&lt;a href="http://idata.cma/cmadaas/"&gt;气象大数据云平台&lt;/a&gt;，旨在提供从数据、算法、接口到计算能力等气象业务需要的全部基础设施。&lt;/p&gt;
&lt;p&gt;数值预报中心在国家气象信息中心的协助下，已开始使用气象大数据云平台中的分布式存储（&lt;strong&gt;二级存储&lt;/strong&gt;）来保存历史归档数据。&lt;/p&gt;
&lt;h2 id="二级存储"&gt;二级存储&lt;/h2&gt;
&lt;p&gt;数值预报业务系统在高性能计算机CMA-PI上生成数据产品，推送到二级存储保存。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;pird.nmic.cn&lt;/code&gt;和&lt;code&gt;piop.nmic.cn&lt;/code&gt;域名访问的普通登陆节点无法直接访问二级存储。
二级存储仅挂载到CMA-PI上的4个特定登陆节点，使用&lt;code&gt;dt.piop.nmic.cn&lt;/code&gt;域名登陆。&lt;/p&gt;
&lt;p&gt;业务系统通过运行在这几个节点上的&lt;code&gt;datatrans&lt;/code&gt;队列，实时向二级存储拷贝部分GRIB2数据产品。
其余的数据会在延后一段时间再自动同步到二级存储。&lt;/p&gt;
&lt;p&gt;挂载的二级存储就相当于本地目录。
但仅有部分用户可以通过域名登陆到挂载二级存储的节点，众多普通账户无法直接使用二级存储上的数据。
尽管我也认为数据分析工作没必要在高性能计算机上完成，但已有的工作大多只针对HPC，所以将二级存储中的历史数据拷贝到HPC是一个迫切的需求。&lt;/p&gt;
&lt;p&gt;CMA-PI提供&lt;strong&gt;cmafs&lt;/strong&gt;工具用于普通用户访问二级存储，提供类似本地文件的操作体验。&lt;/p&gt;
&lt;h2 id="cmafs介绍"&gt;cmafs介绍&lt;/h2&gt;
&lt;p&gt;在CMA-PI上使用下面的命令加载cmafs工具。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;module load apps/cmafs/cmafs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行&lt;code&gt;cma&lt;/code&gt;命令，可以查看cmafs提供的工具。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cma command list:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmacd Move the current working directory
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmals Accessing files under a path to a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmapwd Get the current working directory.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmaput Upload a file or directory to the server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmaget Download a file or directory from a remote serverr
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmarm Delete a file or directory on a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmamv Move a file or directory of a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmamkdir Create a directory in a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmatouch Create a file or modify file properti
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmalocate Find eligible documents on a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmacp Copy a file in a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmachmod Modify permissions on a file or directory in a remote server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmadf Display free disk space
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;包括文件访问、上传、下载等操作，模拟本地文件系统命令，从命令名很容易能猜到命令的功能。&lt;/p&gt;</description></item><item><title>ecFlow笔记：处理空的容器节点</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-10-ecflow-notebook-deal-with-empty-family/</link><pubDate>Tue, 10 Mar 2020 19:55:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-10-ecflow-notebook-deal-with-empty-family/</guid><description>&lt;p&gt;NMC网站将于今年3月份启用新版，重新规划了数据预报的图片产品展示，调整浏览目录结构，大幅度缩减图片数量。&lt;/p&gt;
&lt;p&gt;新版网站要求使用 GRAPES MESO 3km 的图片产品替换 GRAPES MESO 10km 的部分图片产品。&lt;/p&gt;
&lt;p&gt;因为 MESO 3km 模式在00,06,12和18时次积分36小时，而 MESO 10km 在00和12时次积分84小时，03,06,09,15,18,21时次则积分30小时，所以需要对两套系统生成的图片进行合并。
如果 MESO 3km 有数据则使用3km的图片，没有数据则使用10km的图片。&lt;/p&gt;
&lt;p&gt;对于 GRAPES MESO 3km 后处理系统来说，只需要增加新的图片绘制任务。
而现有的 GRAPES MESO 10KM 后处理系统则需要进行修改，关掉3km系统已绘制的那些图片，保留其他任务。&lt;/p&gt;
&lt;p&gt;本文介绍如何修改现有系统，并说明如何处理删减任务后产生的空的容器节点（Family node）。&lt;/p&gt;
&lt;h2 id="修改方式"&gt;修改方式&lt;/h2&gt;
&lt;p&gt;在之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2020/03/2020-03-08-nwpc-system-notebook-build-image-production-suite/"&gt;NWPC业务系统笔记：构建图片产品制作系统&lt;/a&gt;》里提到过，
图片制作系统会使用不同的时效列表。
未修改前的GRAPES MESO 10km后处理系统（简称MESO POST）使用如下的时效列表。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_init_forecast_hour_list&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_list&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour:03}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;an_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; an_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_length&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_list_1&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour:03}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;an_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; an_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_length&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_per_3_list&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour:03}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;an_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; an_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_length&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_per_6_list&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour:03}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;an_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; an_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_length&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_per_12_list&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour:03}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;an_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; an_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;12&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_length&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_per_24_list&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour:03}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;an_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; an_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#34;forecast_length&amp;#34;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按照要求，MESO POST 系统需要构建新的时效列表，去掉与 MESO 3km 重叠的时效。
所以首先要判断 3km 是否预报当前时次，如果有预报，则&lt;code&gt;start_forecast_hour&lt;/code&gt;从&lt;code&gt;37&lt;/code&gt;开始。
构建新时效列表的代码如下所示。&lt;/p&gt;</description></item><item><title>NWPC笔记：构建图片产品制作系统</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-08-nwpc-system-notebook-build-image-production-suite/</link><pubDate>Mon, 09 Mar 2020 12:41:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-08-nwpc-system-notebook-build-image-production-suite/</guid><description>&lt;p&gt;数值预报模式的后处理系统一般生成数据文件和图片文件两种类型的产品。&lt;/p&gt;
&lt;p&gt;本文主要总结最近一段时间移植和构建图片产品制作系统的经验。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;各个业务系统制作图片产品的流程基本相同，包括下面几个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;等待需要的数据文件生成&lt;/li&gt;
&lt;li&gt;绘制图片&lt;/li&gt;
&lt;li&gt;分发图片&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不同图片产品的区别在于需要的数据和制作的数量不同。&lt;/p&gt;
&lt;p&gt;比如&lt;a href="http://nwpc.nmc.cn/list.jhtml?class_id=03021501"&gt;GRAPES MESO模式500hPa高度场图片&lt;/a&gt;从000到084的每个预报时效都对应一张图片产品；
但&lt;a href="http://nwpc.nmc.cn/list.jhtml?class_id=03021504"&gt;24小时2米最高温&lt;/a&gt;只制作024、048和072三张图片产品。&lt;/p&gt;
&lt;p&gt;设计产品制作系统时需要考虑如何组织各种不同的图片产品，方便系统搭建、更新和维护。&lt;/p&gt;
&lt;p&gt;下面首先介绍目前正在使用的两种组织绘图任务的方式。&lt;/p&gt;
&lt;h2 id="两种系统结构"&gt;两种系统结构&lt;/h2&gt;
&lt;p&gt;目前有两种组织图片制作任务的方式。&lt;/p&gt;
&lt;h3 id="以数据时效分类"&gt;以数据时效分类&lt;/h3&gt;
&lt;p&gt;每个图片产品需要的数据总能找到最晚的一个时效，可以将每个绘图任务分配到最晚数据时效对应的容器节点中。
这样每生成一个时效的数据，绘图系统中对应时效的容器节点下所有的绘图任务都可以同时运行。&lt;/p&gt;
&lt;p&gt;比如500hPa高度场图片003时效的图片只需要003时效数据，而24小时2米最高温024时效需要前24小时所有时效的数据。
所以上面两个任务可以分别放到003和024两个容器节点中。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/grapes-gfs-gmf-post-graph-different.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES GFS后处理系统部分图片产品使用数据时效分类方式，003时效比000时效多制作一些产品。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="以产品类型分类"&gt;以产品类型分类&lt;/h3&gt;
&lt;p&gt;如果产品类型较多，并且有不同的数据时效需求和制作数量，可以将每个产品按照类型放到相应的容器节点中。
每个容器节点对应一类产品，可以单独设置数据依赖关系和制作数量。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/grapes-meso-3km-post-tograph.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES MESO 3km 后处理系统使用产品类型分类方式，每个容器节点代表一种产品分类，分类中有多种图片产品。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;以上两种方式对于运行维护来说没有显著的区别，因为绘图程序很少大规模出错。
所以选择哪种方式编写系统取决于ecFlow系统定义代码的编写难度，还需要考虑后期增加新产品是否方便。&lt;/p&gt;
&lt;p&gt;下面着重介绍以产品分类方式的系统如何实现，以时效分类的实现方式类似。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;对于每类图片，都需要实现上一节中提到的三个部分：数据依赖、绘图任务和上传任务。&lt;/p&gt;
&lt;p&gt;下面介绍首先介绍数据检查如何实现，然后介绍如何定义绘图任务，支持批量创建绘图和上传任务。&lt;/p&gt;
&lt;h3 id="数据检查"&gt;数据检查&lt;/h3&gt;
&lt;p&gt;绘制图片前需要检查依赖的数据是否生成。&lt;/p&gt;
&lt;h4 id="直接使用触发器-vs-单独任务检测数据"&gt;直接使用触发器 vs 单独任务检测数据&lt;/h4&gt;
&lt;p&gt;目前有两种数据检查方式。&lt;/p&gt;
&lt;p&gt;因为后处理系统一般都包括数据产品和图片产品制作，所以最常见的方式是直接使用数据转码任务作为触发器。
例如下图所示的3小时降水图片依赖3个时次的数据产品。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/grapes-meso-post-chartos-trigger.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES MESO 后处理系统使用数据转码任务的事件作为触发器&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;该方式应用于除GRAPES MESO 3KM后处理系统外的全部业务系统。&lt;/p&gt;
&lt;p&gt;GRAPES MESO 3KM后处理系统因为历史原因使用另一种方式，单独使用一个任务检测数据产品任务生成的数据。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/grapes-meso-3km-post-tograph-initial.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES MESO 3KM后处理使用绘图部分使用单独的数据检测任务&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;使用单独的任务检测数据会增加系统复杂度，延迟绘图任务触发时间。
但却将绘图任务与数据任务解耦，使得两部分之间没有直接的依赖关系，数据任务的变更不会影响绘图任务。
即便需要修改，也只需要修改数据检测任务，不用修改绘图任务。&lt;/p&gt;
&lt;p&gt;不过，&lt;strong&gt;直接使用触发器&lt;/strong&gt;依旧是构建业务系统的主流方式，简洁明了，建议大家采用。&lt;/p&gt;
&lt;h3 id="绘图任务"&gt;绘图任务&lt;/h3&gt;
&lt;p&gt;逐条构建产品任务会导致代码繁琐，不方便维护。
下面是GRAPES MESO后处理系统中部分代码，大家可以感受一下逐条编写的魅力。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; fm_rundir&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_family(&lt;span style="color:#e6db74"&gt;&amp;#39;cn_plot_10m_wind&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; fm_plot:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a_forecast_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;3km_forecast_hour_list&amp;#39;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; fm_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_task(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;cn_plot_10m_wind_sep_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a_forecast_hour)) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; tk_plot:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ECF_SCRIPT_CMD&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cat &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{ecf_files}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/cn_plot_10m_wind_sep.ecf&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ecf_files&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;meso_chartos&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;attrs&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;ECF_FILES&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_trigger(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/meso_post/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/meso_togrib2/grib2WORK/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/after_data2grib2_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;:grib2OK_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;==set&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name, hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a_forecast_hour
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;FTHOUR&amp;#34;&lt;/span&gt;, a_forecast_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_plot_event_and_meter(tk_plot)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_late_attribute(tk_plot)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; fm_rundir&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_family(&lt;span style="color:#e6db74"&gt;&amp;#39;cn_grapes_meso_APWC&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; fm_plot:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a_forecast_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;forecast_hour_list&amp;#39;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; fm_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_task(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;cn_grapes_meso_APWC_sep_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a_forecast_hour)) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; tk_plot:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ECF_SCRIPT_CMD&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cat &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{ecf_files}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/cn_grapes_meso_APWC_sep.ecf&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ecf_files&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;meso_chartos&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;attrs&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;ECF_FILES&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_trigger(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/meso_post/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/meso_togrib2/grib2WORK/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/after_data2grib2_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;:grib2OK_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;==set&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name, hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a_forecast_hour))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;FTHOUR&amp;#34;&lt;/span&gt;, a_forecast_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_plot_event_and_meter(tk_plot)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_late_attribute(tk_plot)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; fm_rundir&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_family(&lt;span style="color:#e6db74"&gt;&amp;#39;cn_plot_radar_reflectivity&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; fm_plot:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a_forecast_hour &lt;span style="color:#f92672"&gt;in&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;3km_forecast_hour_list&amp;#39;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; fm_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_task(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;cn_plot_radar_reflectivity_sep_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; format(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a_forecast_hour)) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; tk_plot:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ECF_SCRIPT_CMD&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cat &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{ecf_files}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/cn_plot_radar_reflectivity_sep.ecf&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ecf_files&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;meso_chartos&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;attrs&amp;#39;&lt;/span&gt;][&lt;span style="color:#e6db74"&gt;&amp;#39;ECF_FILES&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_trigger(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/meso_post/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/meso_togrib2/grib2WORK/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/after_data2grib2_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;:grib2OK_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{hour}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;==set&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name, hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;a_forecast_hour))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_plot&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;FTHOUR&amp;#34;&lt;/span&gt;, a_forecast_hour)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_plot_event_and_meter(tk_plot)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_late_attribute(tk_plot)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码中，每个产品都包括循环创建绘图任务，指定依赖关系，设定变量。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记：编译V5.X版本</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-06-ecflow-notebook-build-v5/</link><pubDate>Fri, 06 Mar 2020 20:56:03 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-06-ecflow-notebook-build-v5/</guid><description>&lt;p&gt;ecFlow 已开源 V5.X 版本，目前最新版是 5.5.3。
与之前的 V4.X 版本相比，编译源码最大的变化在于 V5 版本可以使用最新版的 Boost。
另外，V5 版本需要使用支持 C++11 的编译器。&lt;/p&gt;
&lt;p&gt;虽然 CMA-PI 上已有 ecFlow 5.4.0 版本，但因为没有使用 Qt Charts 编译，ecFlow UI 缺乏统计图表。
另外仅附带 Python 2 接口，无法使用功能更丰富的 Python 3。&lt;/p&gt;
&lt;p&gt;为了使用带统计功能的 ecFlow UI，我使用自己编译的一系列工具和库来编译 ecFlow。&lt;/p&gt;
&lt;p&gt;下面介绍 ecFlow V5 版本的编译方法，在 CMA-PI 上测试通过。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2020.11 更新：编译 V5.5.3，使用 Anaconda 3 环境&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;CMA-PI 使用 Environment Modules 管理软件包，可以很方便使用自己编译的工具链。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;编译器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;已在 CMA-PI 上编译 GCC 9.2.0。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CMake&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了识别最新版的 Boost，编译最新版的 CMake。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Qt&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;已在 CMA-PI 上编译 Qt 5.10.0。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记：使用late设置超时报警</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-04-ecflow-notebook-use-late-attribute/</link><pubDate>Wed, 04 Mar 2020 14:54:59 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-04-ecflow-notebook-use-late-attribute/</guid><description>&lt;p&gt;最近一段时间，业务系统一直受到串行作业运行卡住的影响。具体表现为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;作业提交到slurm上&lt;/li&gt;
&lt;li&gt;执行ncl程序画图卡住&lt;/li&gt;
&lt;li&gt;运行超时被slurm杀掉&lt;/li&gt;
&lt;li&gt;脚本捕获trap信号，调用 &lt;code&gt;ecflow_client --abort&lt;/code&gt; 与 ecflow 服务通信&lt;/li&gt;
&lt;li&gt;与 ecflow 通讯尚未完成，作业已停止运行，导致ecflow_ui上作业一直处于 active 状态&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;目前尚未定位具体原因，可能需要与HPC运行维护团队一同寻找。&lt;/p&gt;
&lt;p&gt;超时报警一直是业务系统维护的核心需求之一，我们主要通过设置 slurm 的墙钟时间限制。
但上述示例表明即便slurm墙钟时间有效，但作业与ecflow服务的通讯依然可能发生异常，所以需要额外的机制进行报警。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 ecFlow 的 late 属性设置超时报警。&lt;/p&gt;
&lt;h2 id="late属性"&gt;late属性&lt;/h2&gt;
&lt;p&gt;late属性用于指示任务超时，当某个节点被系统任务超时，ecflow仅会标记该节点，而不采取其他动作。
ecflow_ui会在该节点显示late图标，并在late弹出窗口中显示该节点。&lt;/p&gt;
&lt;p&gt;late有下面三种类型：&lt;/p&gt;
&lt;h3 id="submitted"&gt;Submitted&lt;/h3&gt;
&lt;p&gt;节点处于&lt;strong&gt;submitted&lt;/strong&gt;状态不能超过指定时间（格式为&lt;code&gt;[+]hh:mm&lt;/code&gt;）。
Submitted是相对的，所以 &lt;code&gt;+&lt;/code&gt; 被忽略。
如果节点处于&lt;strong&gt;submitted&lt;/strong&gt;状态超过该时长，节点会被设置late标签。&lt;/p&gt;
&lt;h3 id="active"&gt;Active&lt;/h3&gt;
&lt;p&gt;节点必须在某个时间点处于active状态（格式&lt;code&gt;hh:mm&lt;/code&gt;)。
如果节点在该时间点处于&lt;strong&gt;queued&lt;/strong&gt;或&lt;strong&gt;submitted&lt;/strong&gt;状态，会被设置late标签。&lt;/p&gt;
&lt;h3 id="complete"&gt;Complete&lt;/h3&gt;
&lt;p&gt;节点必须在某时间运行结束（格式&lt;code&gt;[+]hh:mm&lt;/code&gt;）。
如果使用相对时间，则表示从节点变为&lt;strong&gt;active&lt;/strong&gt;后的时间，否则节点必须在给定的时间点运行结束。&lt;/p&gt;
&lt;h2 id="方法"&gt;方法&lt;/h2&gt;
&lt;p&gt;定义一个设置late的函数，包括对提交和完成的限制。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add_late_attribute&lt;/span&gt;(node, submitted&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;), complete&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; late &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Late()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; late&lt;span style="color:#f92672"&gt;.&lt;/span&gt;submitted(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;submitted)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; late&lt;span style="color:#f92672"&gt;.&lt;/span&gt;complete(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;complete)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; node&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_late(late)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;默认参数限制节点在&lt;strong&gt;submitted&lt;/strong&gt;状态不能超过10分钟，运行时间不能超过30分钟。&lt;/p&gt;
&lt;h2 id="应用"&gt;应用&lt;/h2&gt;
&lt;p&gt;已对业务系统的ncl画图任务添加late属性。&lt;/p&gt;
&lt;p&gt;节点超时在ecflow_ui上显示如下。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/node-late-icon.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ecflow_ui中显示late图标&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2020/ecflow/node-late-alert-window.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ecflow_ui的late弹出窗口&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://confluence.ecmwf.int/display/ECFLOW/late"&gt;ecflow文档：late&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/chap04/late-attribute/"&gt;ecflow教程中文版：late&lt;/a&gt;&lt;/p&gt;</description></item><item><title>NWPC业务系统笔记：业务后处理系统的版本号策略</title><link>https://blog.perillaroc.wang/post/2020/03/2020-03-01-nwpc-system-notebook-version-strategy-for-operation-postprocessing-system/</link><pubDate>Sun, 01 Mar 2020 15:10:28 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/03/2020-03-01-nwpc-system-notebook-version-strategy-for-operation-postprocessing-system/</guid><description>&lt;p&gt;数值预报中心的确定性模式大多将模式积分与后处理拆成两个子系统。
相对于变更比较稳定的模式积分，后处理系统会面临频繁的产品更新。
将后处理部分分离为单独的系统，能确保频繁的变更不会影响模式积分。&lt;/p&gt;
&lt;p&gt;鉴于缺乏对业务系统&lt;strong&gt;所有&lt;/strong&gt;模块的版本管理和持续集成等机制，目前我们的业务系统更新记录一般都是维护人员手动填写的维护网站更新日志。
随着去年Metcode平台投入使用，我已将负责维护的产品后处理系统都上传到该平台，由版本控制系统来记录各项更新，并减少维护日志的填写。
由此引来一个很棘手的问题：从代码提交记录中很难确定更新上线的具体时间。
为了能准确记录系统变更和上线的时间，需要一种针对后处理系统的版本号策略。&lt;/p&gt;
&lt;p&gt;本文介绍最近设计的一种版本号规则，目前正在部分产品后处理系统中试用。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;数值预报中心的模式系统有严格的版本号规则。
例如当前GRAPES全球模式版本号是2.4，GRAPES区域3km模式版本号是4.4。
对于版本之间的更新没有明确的规定。
后处理系统紧密跟随模式版本升级，属于模式系统的一部分，没有单独的版本规定。&lt;/p&gt;
&lt;p&gt;模式版本的更新次数比较少，使用手动填写的更新日志足以满足需求，无需额外的机制。
但产品的更新非常频繁，所以有必要为后处理单独制定一套版本规则，即兼顾模式版本，又能记录每次产品的更新升级。&lt;/p&gt;
&lt;h2 id="规则"&gt;规则&lt;/h2&gt;
&lt;p&gt;设计的后处理系统版本规则如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;模式版本号-后处理版本号+build.更新日期
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;模式版本号与模式系统一致。
&lt;code&gt;-&lt;/code&gt;符号后面的版本号采用&lt;a href="https://semver.org/lang/zh-CN/"&gt;语义化版本2.0.0规范&lt;/a&gt;制定，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;后处理版本号，&lt;code&gt;X.Y.Z&lt;/code&gt;，具体更新规则见后文说明。&lt;/li&gt;
&lt;li&gt;系统上线日期，&lt;code&gt;YYYYMMDD&lt;/code&gt;，每次系统更新上线都需要使用当天的日期。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如GRAPES区域3km产品后处理系统的某个版本号为：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;4.4-3.0.0+build.20200228
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中4.4是模式版本，3.0.0是后处理系统版本，更新日期是2020年02月28日。&lt;/p&gt;
&lt;p&gt;对于后处理版本号，按如下规定进行递增。&lt;/p&gt;
&lt;p&gt;递增主版本号X：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加新产品&lt;/li&gt;
&lt;li&gt;删除旧产品&lt;/li&gt;
&lt;li&gt;更新产品处理程序&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;递增次版本号Y：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调整流程&lt;/li&gt;
&lt;li&gt;调整产品分发&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;递增修订号Z：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修复流程BUG&lt;/li&gt;
&lt;li&gt;修复ecFlow脚本BUG&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://semver.org/lang/zh-CN/"&gt;语义化版本2.0.0规范&lt;/a&gt;&lt;/p&gt;</description></item><item><title>使用Cobra构建命令行程序</title><link>https://blog.perillaroc.wang/post/2020/02/2020-02-22-use-cobra-to-create-cli-program/</link><pubDate>Sat, 22 Feb 2020 13:19:55 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/02/2020-02-22-use-cobra-to-create-cli-program/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文属于介绍 &lt;strong&gt;NWPC 消息平台&lt;/strong&gt; 系列文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cobra 是一款使用GOLANG实现的命令行库。
官方给出的示例中使用全局变量设置参数，并大量使用init()函数添加命令逻辑。
在各种编程规范中，都不建议使用全局变量，尤其是可变的全局变量。
如果命令行程序比较复杂，使用init()初始化命令逻辑也不容易控制。&lt;/p&gt;
&lt;p&gt;Cobra 作者开发的 Hugo 使用 Cobra 构建命令行程序，但 Hugo 对 Cobra 进行一定的封装，避免使用全局变量。&lt;/p&gt;
&lt;p&gt;本文首先介绍 Cobra 默认的命令构建方式，再介绍一种参考 Hugo 模式简化而来的命令构建方式，在 nwpc-message-client 项目中使用。&lt;/p&gt;
&lt;h2 id="cobra-默认的命令构建方式"&gt;Cobra 默认的命令构建方式&lt;/h2&gt;
&lt;p&gt;cobra 默认使用全局变量构建子程序和命令选项，并在每个子命令文件的&lt;code&gt;init()&lt;/code&gt;函数中将子命令注册到主命令中。&lt;/p&gt;
&lt;p&gt;下面的代码来自 nwpc-data-client 项目。&lt;/p&gt;
&lt;p&gt;主命令在cmd包的root.go文件创建，并提供 &lt;code&gt;Execute&lt;/code&gt; 函数供 main 文件调用命令。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cmd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;github.com/spf13/cobra&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;os&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rootCmd&lt;/span&gt; = &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cobra&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Command&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Use&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;nwpc_data_client&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Short&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Data client for NWPC.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Long&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;A data client for GRAPES models in NWPC.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Run&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cmd&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cobra&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Command&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; []&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;cmd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Help&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Execute&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rootCmd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Execute&lt;/span&gt;(); &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Println&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;os&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Exit&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个子命令在单独的文件中创建，例如下面代码创建&lt;code&gt;local&lt;/code&gt; 子命令的全局变量，使用全局变量定义命令选项，并在 &lt;code&gt;init&lt;/code&gt; 函数中将该命令注册到主命令。&lt;/p&gt;</description></item><item><title>NWPC业务系统笔记：检查单个时次是否运行完成</title><link>https://blog.perillaroc.wang/post/2020/02/2020-02-20-nwpc-system-notebook-check-cycle-complete/</link><pubDate>Thu, 20 Feb 2020 20:01:37 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/02/2020-02-20-nwpc-system-notebook-check-cycle-complete/</guid><description>&lt;p&gt;数值预报业务系统每天会执行多个循环，例如 GRAPES 全球预报系统每天计算 00、06、12 和 18 共四个时次的预报。
在每天运行的最后，会有一个任务用于清理几天前运行所占用的空间。
整个系统的结构，如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image%2Fblog%2F2020%2Fecflow%2Fgrapes-gfs-gmf-post-suite.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES 全球预报后处理系统的示意图，每天有四个时次，在第二天 02:00 UTC 会执行 housekeep_final 任务清理空间&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;ecFlow 只有在某个 suite 所有任务都运行完成才会自动滚动到下一天。
如果哪个任务没有正常完成，系统就会卡在这一天，影响后续任务的执行。
最近一段时间，因为任务运行超时被 slurm 杀掉，但任务没有被 aborted，导致任务一直处于 active 状态，容易被值班人员忽略。&lt;/p&gt;
&lt;p&gt;目前还没有找到具体的原因。
推测可能是在系统出错时调用 ecflow_client 命令耗时较长，超过被 slurm 杀掉的作业允许的执行时间，导致 ecflow 服务没有接收到 aborted 信号。&lt;/p&gt;
&lt;p&gt;当前的系统设计无法处理这种情况。
本文介绍一种检查单个时次是否运行完成的方法，为值班人员提供明确的提示信息。&lt;/p&gt;
&lt;h2 id="原理"&gt;原理&lt;/h2&gt;
&lt;p&gt;业务系统在设定 housekeeping 任务启动时间时，假定该时间点当天所有的时次已经完成。
所以，可以设置一组与 housekeeping 同时启动的任务，分别检查各个时次是否完成。
如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image%2Fblog%2F2020%2Fecflow%2Fmeso-post-check-complete.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES 区域模式系统各个时次的检查任务&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;ecFlow 提供 complete 触发器，用于在符合条件的情况下跳过某个任务，但 complete 只支持 event 事件，不支持节点。
所以需要在脚本中手动检测任务是否完成。&lt;/p&gt;
&lt;p&gt;ecFlow_client 命令无法直接获取某个节点的运行状态。
下面的代码使用 Python API 接口返回指定节点的运行状态字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; __future__ &lt;span style="color:#f92672"&gt;import&lt;/span&gt; print_function
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; argparse
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; ecflow
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser &lt;span style="color:#f92672"&gt;=&lt;/span&gt; argparse&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ArgumentParser()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_argument(&lt;span style="color:#e6db74"&gt;&amp;#34;--host&amp;#34;&lt;/span&gt;, help&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ecflow host&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_argument(&lt;span style="color:#e6db74"&gt;&amp;#34;--port&amp;#34;&lt;/span&gt;, help&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ecflow port&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_argument(&lt;span style="color:#e6db74"&gt;&amp;#34;--node-path&amp;#34;&lt;/span&gt;, help&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;node path&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;parse_args()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; client &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ecflow&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Client(args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;host, args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;port)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sync_local()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; defs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_defs()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; node &lt;span style="color:#f92672"&gt;=&lt;/span&gt; defs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find_abs_node(args&lt;span style="color:#f92672"&gt;.&lt;/span&gt;node_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; node &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; str(node&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get_dstate())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(status)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; main()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用下面的命令获取节点状态：&lt;/p&gt;</description></item><item><title>在Docker中使用Anaconda</title><link>https://blog.perillaroc.wang/post/2020/01/2020-01-30-use-anaconda-in-docker/</link><pubDate>Thu, 30 Jan 2020 15:02:32 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/01/2020-01-30-use-anaconda-in-docker/</guid><description>&lt;p&gt;在 &lt;a href="https://github.com/perillaroc/ploto"&gt;ploto&lt;/a&gt; 项目中，我使用 python 的 docker 镜像构建 esmdiag 的镜像。
因为 debian 默认的 cdo 无法解析项目用到的 NetCDF 格式数据，所以需要在构建镜像时编译 cdo 源码，耗费大量时间。&lt;/p&gt;
&lt;p&gt;最近基于 Anaconda 开发了 &lt;a href="https://github.com/nwpc-oper/nwpc-graphics"&gt;nwpc-oper/nwpc-graphics&lt;/a&gt; 项目，该项目部署在安装了 SUSE 操作系统的服务器上，没有正版支持，无法在线安装软件。
经搜索发现，可以使用 conda 安装 NCL 软件包，安装后可以执行业务系统使用的 NCL 脚本。&lt;/p&gt;
&lt;p&gt;因此，我准备将 ploto 项目中的基础镜像从 Python 替换为 Anaconda。&lt;/p&gt;
&lt;h2 id="选择镜像"&gt;选择镜像&lt;/h2&gt;
&lt;p&gt;Anaconda 是一个商业公司，相关的 Docker 镜像由该公司提供。
访问下面网址，可以看到该公司提交的镜像：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hub.docker.com/u/continuumio/"&gt;https://hub.docker.com/u/continuumio/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;镜像主要分为 anaconda 和 miniconda 两种类型。
如果只需要 conda 环境，可以选择占用磁盘空间较小的 miniconda 镜像。&lt;/p&gt;
&lt;h2 id="创建-env"&gt;创建 env&lt;/h2&gt;
&lt;p&gt;使用 conda 安装 NCL 需要单独创建一个 env，在默认的 env 中无法正常安装。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;continuumio/miniconda&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RUN&lt;/span&gt; conda create -n ncl_stable -c conda-forge ncl cdo imagemagick &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; conda clean -y -a&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CMD&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;conda&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-n&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;ncl_stable&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/bin/bash&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-c&amp;#34;&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的 dockerfile 创建 ncl_stable 环境，并安装 ploto 项目需要使用的 ncl、cdo 和 imagemagick。&lt;/p&gt;</description></item><item><title>使用Jupyter Notebook显示NCL绘图</title><link>https://blog.perillaroc.wang/post/2020/01/2020-01-16-show-ncl-plot-in-jupyter-notebook/</link><pubDate>Thu, 16 Jan 2020 20:39:11 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/01/2020-01-16-show-ncl-plot-in-jupyter-notebook/</guid><description>&lt;p&gt;数值预报中心的大部分业务系统都使用 GrADS 或者 NCL 绘制图片产品。
例如 GRAPES GFS 后处理系统由 ecFlow 构建，并使用 shell 调用 ncl 脚本绘制图片。&lt;/p&gt;
&lt;p&gt;最近尝试使用 Jupyter Notebook，对业务系统的后处理绘图脚本进行了二次加工，封装现有的 NCL 脚本提供便捷的图形绘制方法。&lt;/p&gt;
&lt;h2 id="ncl脚本介绍"&gt;NCL脚本介绍&lt;/h2&gt;
&lt;p&gt;以 GRAPES GFS 后处理系统的绘图脚本为例说明。
NCL 脚本既使用环境变量，也使用命令行参数，同时某些脚本还需要读取运行目录下的文本文件。&lt;/p&gt;
&lt;p&gt;业务系统的后处理使用了通用的绘图库，所以需要设置绘图库的路径。
另外，绘图还需要使用到某些特殊的环境变量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GEODIAG_ROOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/g1/u/nwp_pd/GEODIAG
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GEODIAG_TOOLS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/g1/u/nwp_pd/GEODIAG/tools
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GRAPHIC_PRODUCT_LIB_ROOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;NCLLIB&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GRAPHIC_PRODUCT_SCRIPT_ROOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GRAPHIC_PRODUCT_LIB_ROOT&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export FORECAST_DATA_FORMAT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;grib2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export FORECAST_DATA_CENTER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;ecmwf&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本地文本文件用于指定起报时间、预报时效和预报时间。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export NEWDATE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;smsdate $startdate +&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;fhr&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &amp;gt; grapes_meso_date &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;${startdate}${fhr}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;${NEWDATE}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;命令行参对于大部分 NCL 脚本都相同，包括时间相关参数，输入数据目录，输出图片目录等。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ncl initial_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$initial_time &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; min_forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$min_forecast_time &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_forecast_time&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$max_forecast_time &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forecast_time_interval&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$forecast_time_interval &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;$data_path&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; graphic_output_home&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;$graphic_output_home&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $file_name
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用python执行ncl脚本"&gt;使用Python执行NCL脚本&lt;/h2&gt;
&lt;p&gt;在 Python 调用 NCL 脚本可以使用 subprocess 包配置好环境变量后直接执行 &lt;code&gt;ncl&lt;/code&gt; 命令。
但 Python 脚本运行的环境可能无法直接使用 NCL，例如在 conda 单独的 env 中安装 NCL 库。
这种情况下，可以在 Python 中调用一个 shell 脚本，在 shell 中首先载入NCL环境，再执行 NCL 命令。&lt;/p&gt;</description></item><item><title>2019年个人总结</title><link>https://blog.perillaroc.wang/post/2020/01/2020-01-05-2019-summary/</link><pubDate>Sun, 05 Jan 2020 11:23:50 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/01/2020-01-05-2019-summary/</guid><description>&lt;p&gt;又到了每年一度的年度总结大会。在新年伊始，总会回顾过去一年的人生经历，并为接下来的一年制定雄心勃勃的计划。&lt;/p&gt;
&lt;p&gt;去年是与众不同的一年，迎来了女儿的诞生，我也面临从角色到生活的各种挑战，经历了很多事情，也看到了自己的不足。
以后也将变得与之前完全不同，我的未来计划里面增加了另一个小生命。
看着女儿逐渐的长大，我也不能再逃避现实，忽视规划了，我的一举一动都可能会影响到女儿未来的成长。&lt;/p&gt;
&lt;h2 id="生活"&gt;生活&lt;/h2&gt;
&lt;p&gt;虽然这部分放到了最前面，但每次都是最后才写，导致每次写得都不是很多。&lt;/p&gt;
&lt;p&gt;这次我也简要地写下，后面有时间再慢慢总结。&lt;/p&gt;
&lt;p&gt;自从女儿出生，我的生活有了翻天覆地的变化。对我来说，转变角色往往需要很长的时间。
再加上7月份搬到单位的公寓，生活方式有了一些变化，可能直到现在我也没有完全适应。
无论是作息时间安排，还是生活中的各种事项，我都需要去适应，调整心态，尽量给家人以正能量。
不清楚这样的调整会有什么样的效果，但我必须尽全力去面对新的生活，去承担自己的职责。&lt;/p&gt;
&lt;p&gt;住在单位附近最好的一点就是能多陪女儿，而我在这点上好像做得不够好。
今年我一定要时刻牢记自己最重要的职责：陪女儿一同成长。&lt;/p&gt;
&lt;h2 id="flag"&gt;FLAG&lt;/h2&gt;
&lt;p&gt;FLAG就是用来打脸的，看来去年也是如此。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/summary/flag-2019-12.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;FLAG at 2019.12&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="个人工作总结"&gt;个人工作总结&lt;/h2&gt;
&lt;p&gt;我们单位的工作总结在去年12月中旬就已经结束了，我将个人工作总结的内容简要介绍下。&lt;/p&gt;
&lt;h3 id="业务系统集成"&gt;业务系统集成&lt;/h3&gt;
&lt;p&gt;数值预报业务系统集成是我最核心的工作任务之一。&lt;/p&gt;
&lt;h4 id="业务系统建设"&gt;业务系统建设&lt;/h4&gt;
&lt;p&gt;下面张图展示了2019年下半年Metcode投入应用以来与业务系统更新相关的代码提交数。
可以看到除了十月份我去参加培训以外，几乎每周都会对业务系统进行改动。
这对于我们已成立十年的业务中心来说，显得过于频繁。
当然，业务系统更新也和硬件环境的变动有关，去年我们继续将业务系统从IBM切换到PI-曙光，也将二级存储加入到业务流程中。
外部依赖环境的变化是系统更新的重要因素。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/summary/metcode-calendar.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;2019年下半年Metcode投入应用以来与业务系统集成相关的代码提交日历&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;我去年参与维护的主要业务系统主要是配合其他科室完成相关系统的建设、更新和部署，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;建设：GRAPES TYM，MUVOS&lt;/li&gt;
&lt;li&gt;更新：GRAPES GFS POST&lt;/li&gt;
&lt;li&gt;部署：MESO 3km POST，GRAPES TYM POST&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;正如我去年在几篇文章中描述的，这项任务正是目前我工作的困境所在。&lt;/p&gt;
&lt;p&gt;现有的业务系统建设任务基本属于重复性劳动，很难在职称晋升中体现为工作业绩。
尽管从入职以来就一直听说ECMWF在构建对象化的业务系统流程，但始终没有看到具体的示例，也没有看到开展此类研究的动力和收益。
所以，即便我不能否认业务系统集成方面还有很多可以深入研究的内容，尤其是在最近看了&lt;a href="https://www.ecmwf.int/en/learning/workshops/building-reproducible-workflows"&gt;ECMWF REPWORK 19&lt;/a&gt;的一些报告后，但我依然无法确定在这方面投入时间是否能带来想要的收益。当然这就会陷入一个死循环，无法摆脱重复劳动的陷阱，又不愿意迈出试探的一步。&lt;/p&gt;
&lt;p&gt;我目前主要负责与数值模式本身关系不大的产品制作系统，与数值模式的业务系统没有太多的相似性，受众面更小。
即便我们单位准备开展这方面的研究，也不适合由我来推进，所以今年在业务系统集成方面的任务还是延续去年，按照部门的安排完成我负责的工作。&lt;/p&gt;
&lt;h4 id="运行效率"&gt;运行效率&lt;/h4&gt;
&lt;p&gt;业务系统建设不只是流程和脚本的编写，我们在很多时候需要寻找运行效率和维护成本的平衡点。&lt;/p&gt;
&lt;p&gt;以后处理系统中一个常见的任务来说明。后处理系统需要检测数据文件是否完整。
当前业务系统中有两种检测数据完整性的方法：单任务逐时效检测和多任务同时检测。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/summary/grapes-3km-post-check.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;单任务逐时效检测&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/summary/grapes-tym-check-ncep.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;多任务同时检测&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;这两种方式各有利弊。我开发了一个并行程序，综合这两种方式的优点，实现单个任务并发检测多个数据文件的功能。&lt;/p&gt;
&lt;p&gt;程序源代码请访问 &lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-oepr/nwpc-data-client&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;这项工作已在《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-12-05-nwpc-system-notebook-check-data-in-parallel/"&gt;NWPC业务系统笔记：并行检查数据&lt;/a&gt;》博文中介绍。&lt;/p&gt;
&lt;h4 id="分发速度"&gt;分发速度&lt;/h4&gt;
&lt;p&gt;我们科一直关注我们系统提供服务的能力，因为用户发现产品缺失后会直接联系我们科的值班同事。
但产品分发速度可能并不是我们整个处室关注的重点，我在过去的报告中也很少能看到有同事介绍这方面的工作。&lt;/p&gt;
&lt;p&gt;去年GRAPES TYM升级业务评审时，预报司的领导说不要因为优化太小而不做，整个业务系统的分发速度正是来自每个任务节省出来的1-2分钟。
所以我今年也关注如何从流程方面提高产品分发速度，这也是目前来说我们科在提高产品分发速度方面唯一能做的事情。&lt;/p&gt;
&lt;p&gt;去年拆分了GRAPES GFS产品制作任务，将能同时做的产品尽量同时做，并且对产品进行分级，保障核心产品尽早分发。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/summary/gfs-post-create-data.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>ecflow学习笔记：节点状态监控工具V2</title><link>https://blog.perillaroc.wang/post/2020/01/2020-01-01-ecflow-notebook-ecflow-watchman-v2/</link><pubDate>Wed, 01 Jan 2020 09:19:01 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2020/01/2020-01-01-ecflow-notebook-ecflow-watchman-v2/</guid><description>&lt;p&gt;本文介绍使用 ecFlow C++ API 构建的节点状态监控工具。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;之前的文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-20-ecflow-notebook-ecflow-watchman/"&gt;ecflow学习笔记：节点状态监控工具&lt;/a&gt;》介绍使用 ecflow 的 Go 客户端开发节点状态监控工具。&lt;/p&gt;
&lt;p&gt;经过一个多月的连续运行，发现该程序有严重的内存泄漏问题。虽然经过修改，解决了部分问题，但内存泄漏依然存在。&lt;/p&gt;
&lt;p&gt;该程序使用 SWIG 连接 ecflow c++ 接口，从 c++ 接口返回字符串给 goroutine，将信息组织成 json 字符串，再发送给 redis 数据库。&lt;/p&gt;
&lt;p&gt;内存泄漏是因为字符串没有被删除，包括 SWIG 接口返回的字符串，和构造的JSON字符串。虽然 inuse_space 很小，但 alloc_space 的内存似乎没有被释放。
pprof 的图示如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="%22https://cdn.perillaroc.wang/image/blog/2019/ecflow/watchman-go-version-memory-leak-graph.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ecflow_watchman 内存占用图示&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;可以看到，两个部分占用内存基本相等，可能由同一个问题导致。查看内存占用的代码段：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/ecflow/watchman-go-version-memory-leak-source.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ecflow_watchman 内存泄漏代码段&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;可以看到，从 ecflow 获取的状态字符串是内存消耗的主要原因。但程序实际使用的内存较少，不知道为什么 GC 没有回收掉不用的内存。后面会进一步分析原因。&lt;/p&gt;
&lt;p&gt;既然使用 SWIG 的程序有这样的问题，还不如直接用 C++ 实现。
下面介绍基于 &lt;a href="https://github.com/nwpc-oper/ecflow-client-cpp"&gt;nwpc-oper/ecflow-client-cpp&lt;/a&gt; 构建的节点状态监控工具V2。&lt;/p&gt;
&lt;h2 id="程序结构"&gt;程序结构&lt;/h2&gt;
&lt;p&gt;新版的ecflow-watchman与老版流程一致。从命令行参数指定的配置文件中读取任务列表，启动多个线程（v1 版为 goroutine）同时获取多个 ecflow 服务的状态，并保存到 redis 数据库中。
程序结构示意图如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/ecflow/ecflow-watchman-v2.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ecflow-watchman程序结构&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;下面介绍几个关键部分的实现。&lt;/p&gt;
&lt;h3 id="多线程"&gt;多线程&lt;/h3&gt;
&lt;p&gt;v1 版本中使用 GO 语言提供的 goroutine 以协程的方式实现同时监听多个 ecflow 服务，但 C++ 没有内置的协程库（C++20 标准据说有协程库），所以考虑使用多线程来替代。&lt;/p&gt;</description></item><item><title>使用Airflow运行诊断绘图任务</title><link>https://blog.perillaroc.wang/post/2019/2019-12-29-use-airflow-to-run-plot-task/</link><pubDate>Sun, 29 Dec 2019 11:14:18 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-12-29-use-airflow-to-run-plot-task/</guid><description>&lt;p&gt;本文介绍如何使用Airflow构建工作流实现诊断绘图任务。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;我在2017年开始的青年基金项目中实现了一套分布式调度系统（&lt;a href="https://github.com/perillaroc/ploto"&gt;perillaroc/ploto&lt;/a&gt;)，用于执行批量绘图任务。
今年将该系统应用到地球模式系统诊断平台建设项目中，集成了&lt;a href="https://github.com/dongli/esmdiag"&gt;dongli/esmdiag&lt;/a&gt;项目的部分诊断绘图功能。&lt;/p&gt;
&lt;p&gt;项目将单个的诊断绘图任务看成由多个步骤（step）组成的任务，步骤分为多个类型，包括数据获取、数据处理、图形绘制等。
绘图服务（plot service）会依次调用相应的模块顺序执行每个步骤。
目前绘图服务只支持串行执行步骤，但诊断绘图任务中的部分步骤都可以并行执行，例如获取并处理多个要素场可以同时进行。
多个这样的步骤考虑相互依赖关系可以组成一个DAG图，也就是工作流的形式。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用Airflow构建DAG图，执行批量绘图任务。&lt;/p&gt;
&lt;h2 id="诊断绘图任务"&gt;诊断绘图任务&lt;/h2&gt;
&lt;p&gt;下面以esmdiag中climo/precip诊断为例说明诊断绘图任务的常见流程。&lt;/p&gt;
&lt;p&gt;esmdiag诊断包使用cdo和NCL脚本将输入数据转换成绘图脚本需要的中间数据，然后使用NCL脚本绘图。
地球模式系统诊断平台中集成的esmdiag包增加对数据接口的支持，数据文件不再保存到本地而是通过数据平台的接口获取。
诊断任务的串行流程如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/esmdiag-airflow-serial.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;诊断绘图任务climo/precip串行流程&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;图中蓝色步骤是调用数据平台接口检索数据，绿色步骤是使用cdo对数据进行操作，黄色步骤是调用NCL脚本绘图。&lt;/p&gt;
&lt;p&gt;目前使用的数据接口获取的数据是逐月保存的，而绘图需要的中间文件是每个变量保存到一个文件中，所以需要使用cdo将变量提取到单个文件中。上面的提取变量步骤可以并行执行，两个数据获取任务也可以并行。&lt;/p&gt;
&lt;p&gt;将上述流程组织成DAG图的形式如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/esmdiag-airflow-dag.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;诊断绘图任务climo/precip工作流流程&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;图中有两组数据获取、处理步骤，第一组中有四个并行的数据处理步骤。两组操作都完成后，执行绘图任务。&lt;/p&gt;
&lt;h2 id="使用airflow构建dag"&gt;使用Airflow构建DAG&lt;/h2&gt;
&lt;p&gt;先介绍下如何使用Airflow构建上面的DAG图。下面的代码只展示基本代码框架，省略了大量细节，无法真正运行。&lt;/p&gt;
&lt;h3 id="构建dag对象"&gt;构建DAG对象&lt;/h3&gt;
&lt;p&gt;Airflow中每个工作流项目都是一个DAG对象，工作流中的每个任务都是一个Operator对象。&lt;/p&gt;
&lt;p&gt;每个DAG有一个唯一的ID，通过&lt;code&gt;dag_id&lt;/code&gt;指定。&lt;/p&gt;
&lt;p&gt;DAG可以设置一些默认参数，传递给DAG中的所有task。诊断平台中的诊断任务都是相互独立的，前一次任务出错不应该影响下一次任务，所以将&lt;code&gt;depends_on_past&lt;/code&gt;参数设置为&lt;code&gt;false&lt;/code&gt;。开始时间参数&lt;code&gt;start_date&lt;/code&gt;对我们的诊断任务没有意义，但每个DAG必须设置，所以可以设置任意的时间。&lt;/p&gt;
&lt;p&gt;DAG通过&lt;code&gt;schedule_interval&lt;/code&gt;设置调度方式，诊断平台中的每个任务都是由客户端请求驱动的，不需要定时启动，所以直接设置为None。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; airflow.utils.dates
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; airflow.models &lt;span style="color:#f92672"&gt;import&lt;/span&gt; DAG
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; airflow.operators.python_operator &lt;span style="color:#f92672"&gt;import&lt;/span&gt; PythonOperator
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;args &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;owner&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ploto&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;depends_on_past&amp;#39;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;start_date&amp;#39;&lt;/span&gt;: airflow&lt;span style="color:#f92672"&gt;.&lt;/span&gt;utils&lt;span style="color:#f92672"&gt;.&lt;/span&gt;dates&lt;span style="color:#f92672"&gt;.&lt;/span&gt;days_ago(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dag_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ploto_esmdiag_climo_precip&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dag &lt;span style="color:#f92672"&gt;=&lt;/span&gt; DAG(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dag_id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dag_id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; default_args&lt;span style="color:#f92672"&gt;=&lt;/span&gt;args,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; schedule_interval&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="创建工作目录"&gt;创建工作目录&lt;/h3&gt;
&lt;p&gt;为每个诊断任务创建一个唯一的运行目录。
为了保持一致性，后续所有的任务都使用&lt;code&gt;PythonOperator&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;create_dir_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PythonOperator(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;create_work_dir&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dag
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="获取并处理数据"&gt;获取并处理数据&lt;/h3&gt;
&lt;p&gt;本组操作包括两步：运行一个任务检索包含四个变量的数据，同时运行四个任务从文件中提取变量。&lt;/p&gt;
&lt;p&gt;每个任务都有唯一的task_id，并通过&lt;code&gt;set_upstream&lt;/code&gt;等函数设置任务之间的依赖关系。
任务需要绑定到DAG中，同一个任务只能绑定到单一的DAG中，后面会介绍如何动态构建任务实现代码复用。&lt;/p&gt;</description></item><item><title>日记：关于交互诊断软件开发任务的一些想法</title><link>https://blog.perillaroc.wang/post/2019/2019-12-20-diary-some-thoughts-about-gidat-project/</link><pubDate>Fri, 20 Dec 2019 20:50:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-12-20-diary-some-thoughts-about-gidat-project/</guid><description>&lt;p&gt;今天上午科里和领导与华信公司讨论明年与工程项目相关的各项工作计划。
加上昨天科里对明年工作计划的讨论，以及本周早些时候单独与华信公司的交流，我已坚定近两年一直都没有下定的决心：&lt;strong&gt;退出交互诊断软件开发任务&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;我从2013年入职起，就一直在开发数值预报模式交互诊断桌面软件。历经十二五科技支撑项目（2012-2017年）和海洋工程一期（2018-2020年），累积开发已超过六年时间。
期间经历过二次代码重写和四次大版本变动，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux原型开发（2013年）&lt;/li&gt;
&lt;li&gt;Linux使用后台NCL批量绘图（2014年-2015年）&lt;/li&gt;
&lt;li&gt;Linux使用Qwt实时绘图（2016年）&lt;/li&gt;
&lt;li&gt;移植到Windows使用Qwt实时绘图（2017年）&lt;/li&gt;
&lt;li&gt;Windows使用GIS实时绘图（2018年）&lt;/li&gt;
&lt;li&gt;Windows重写架构（2019年）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以看到，几乎每年都会对整个软件进行大范围的改动，导致多年来一直在重复开发，在功能上没有形成良性的持续迭代。
所以这么多年来一直没能拿出一个能够推广应用的版本。&lt;/p&gt;
&lt;p&gt;重新回顾下我从2013年到2019年的工作总结，可以发现很有意思的事情。
在2018年以前，我一直以交互诊断软件为我的核心工作任务，放在第一位介绍。而从2018年开始，诊断软件已基本放在总结的最后部分，不再作为核心任务。
其实，我应该在2018年就应该果断地退出这项任务，但新的工程项目给了我希望，让我错误地认为软件没有做出来是公司的问题，并让我在2019年初依然认为自己可以做出一定的成果。&lt;/p&gt;
&lt;p&gt;但是，我其实早就应该意识到，因为自己的局限性，这项工作一定不会有拿得出手的成果。&lt;/p&gt;
&lt;h2 id="局限"&gt;局限&lt;/h2&gt;
&lt;p&gt;最大的问题在于我从事的其它工作与数值模式诊断没有一点儿联系，我一直以来都不清楚交互诊断工具该做成什么样子。
这显然与我没有深入了解和学习数值模式和诊断方法有关系。我们不能将自己局限在已了解的领域中，应该积极拥抱新的挑战。
不过，直面挑战不是一件很容易的事情，我从入职以来一直将自己限制在IT相关的领域，而没有花心思去了解业务，了解数值预报模式系统。&lt;/p&gt;
&lt;p&gt;另一个问题在于我们缺乏一整套支持交互分析的完整工具包，包括数据平台、解码工具、绘图引擎等等。交互分析涉及到的每一个部分，都需要项目组自己去寻找解决方案。
这么多年来光是绘图引擎我们就尝试了三套完全不同的方案，大量的精力都浪费在交互软件与绘图引擎之间的匹配上。
另外，交互工具项目一直都强调同时具备实时绘图和批量绘图功能，但2018年之前我们一直使用NCL实现后台批量绘图，导致我们需要同时维护两种绘图和显示方案，给整个软件带来繁重的开发量。
尽管2019年我已经意识到这个问题，开始强调前后台使用同样的技术实现，但借助第三方公司来提供绘图引擎对我来说不是一个很好的选择。
明年会实现简化版本的后台批量绘图，但未来是否还需要沿着现有的技术路线前进，我个人持怀疑态度。&lt;/p&gt;
&lt;p&gt;数据平台是构建数据分析软件的基础，尤其是我们需要在桌面电脑Windows中上运行交互工具，但数据却保存到HPC上。
今年我们将业务数据和部分实验数据保存到二级存储中，并将之前开发的数据平台部署到连接二级存储的Linux服务器中，接入业务系统输出的数据。
明年会对接数据平台，部分解决数据接入的问题。&lt;/p&gt;
&lt;p&gt;但还是需要面对一个问题：我们是否需要Windows下的桌面软件？这也是最近几天讨论工作时，我与领导最大的分歧所在。&lt;/p&gt;
&lt;h2 id="纷争"&gt;纷争&lt;/h2&gt;
&lt;p&gt;鉴于连续六年失败的开发经历，我认为开发桌面版的交互分析软件投入太大，以目前单人负责一个项目的组织方式，对于我来说难以实现。&lt;/p&gt;
&lt;p&gt;我们有很多工程项目，做的事情往往都是一样的：管理数据，分析数据，制作产品，展示结果。正如我之前的博文提到，我们不同项目之间缺乏成果共享，导致严重的重复建设。
我个人对绘制气象图形不是很擅长，但交互分析软件就是要绘制出模式研发人员需要的图形，导致做出来的效果距离实际应用还有很大的差距。
而图形绘制仅仅是软件中的一个组件，其余诸如数据接入、交互分析、元数据管理等等也需要大量设计和开发工作。
每一块都需要开发，即便通过工程项目与公司合作，我也觉得力不从心。我本身的项目管理能力也是一个大问题。&lt;/p&gt;
&lt;p&gt;我建议改变技术路线，抛去桌面交互分析工具的想法，开发基于绘图脚本的批量绘图工具和基于Web的显示工具，不再强调交互功能。
初始版本并不需要提供强大的定制和交互功能，满足研发人员的部分需求，能应用起来就可以了。
领导担心这样的思路与已应用的A工具没有区别，会让人觉得这样的工具能被A工具覆盖，不是我们科应该做的。
我也觉得领导的担心很有道理，上面的提议就是完全仿照A工具开发诊断工具，与直接放到A工具中没有任何区别。针对这点，我又提了下面的建议。&lt;/p&gt;
&lt;p&gt;目前多个工程项目在开发基于WebGIS的产品展示工具，我建议利用其它工程项目的成果，开发基于Web的交互工具。
从公司角度看，懂Web的人才比懂C++/Qt的人才更多也更容易招到。气象中心除了Micaps外也开发了MOAP平台。
不能打包票说以后的模式数据分析都会基于Web技术在浏览器中进行，但我觉得应该是未来的趋势。
简单的分析操作完全可以由浏览器来实现，复杂的分析操作可以直接写代码实现。
即便真的需要桌面工具，诸如Electron的工具也可以将Web网站做成桌面软件。
这个技术路线同样会涉及到与其他科室的任务有重叠，所以和之前的建议一样，不被认可。&lt;/p&gt;
&lt;p&gt;所以，最后我建议领导考虑让其他更懂模式诊断的同事接手这个项目。如果再由我负责，沿着现有的技术路线做下去，永远不会有结果。
领导说我们的试验工具做了15年，经历了几波人员变动，到现在终于有了可以应用的成果。只要坚持不懈的钻研，总能做出来。
但我已经做了6年，可以想一想还需要多长时间才能拿出来成果。&lt;/p&gt;
&lt;p&gt;有一说一，我很佩服领导的工作态度，领导之所以成为领导，就是因为有我们所不具备的能力。&lt;/p&gt;
&lt;h2 id="未来"&gt;未来&lt;/h2&gt;
&lt;p&gt;讨论当然没有最终的结果。我会负责到明年海洋工程一期项目验收，后续的工作我会建议重新讨论并安排。&lt;/p&gt;
&lt;p&gt;工程项目的事情很难说清楚，我相信包括我在内的很多同事都意识到现在项目执行所面临的一些问题，但想改变单位的工作惯例是一件很困难的事情。
办公室领导在年终总结时也提到明年会考虑工程项目的管理问题。
无论明年是否有所改变，我都期望后面的工程项目能考虑核心技术是否应该由我们的员工负责技术设计和开发，并在执行上考虑项目之间的成果共享。&lt;/p&gt;
&lt;p&gt;从我所在的科的角度来讲，我希望我们能像信息中心学习，设计一套通用底层框架，支撑各种应用级别的工程项目。
应用项目所涉及的部分往往不是我们的日常工作，底层框架正是我们所擅长的。
想法是美好的，但现实会怎么样就不好说了。我们评价项目成果往往只会考虑单一个人，而不是某个团队的。&lt;/p&gt;
&lt;p&gt;无论如何，我觉得未来我应该把精力投入到对提高工作效率有帮助的任务和自己感兴趣的任务中。&lt;/p&gt;</description></item><item><title>NWPC业务系统笔记：并行检查数据</title><link>https://blog.perillaroc.wang/post/2019/2019-12-05-nwpc-system-notebook-check-data-in-parallel/</link><pubDate>Thu, 05 Dec 2019 20:52:18 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-12-05-nwpc-system-notebook-check-data-in-parallel/</guid><description>&lt;p&gt;之前的一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-09-16-nwpc-system-notebook-check-output-data/"&gt;NWPC业务系统笔记：检查输出数据&lt;/a&gt;》中详细介绍了目前NWPC数值预报业务系统检查输出数据的方法。&lt;/p&gt;
&lt;p&gt;其中提到目前数据有两种检查方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多个作业并发检测&lt;/li&gt;
&lt;li&gt;单个作业循环检测&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两种方式各有利弊，详细分析查看该文档。&lt;/p&gt;
&lt;p&gt;本文介绍一种使用单个作业并行检测数据文件的方法，综合上面两种方式的优点，寻找效率和资源占用的平衡。&lt;/p&gt;
&lt;h2 id="原理"&gt;原理&lt;/h2&gt;
&lt;p&gt;单任务并行检测数据文件的原理如下图所示。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-data-checker.png"&gt;
&lt;/figure&gt;

&lt;p&gt;主程序根据预报时效列表生成一系列的goroutine。&lt;/p&gt;
&lt;p&gt;每个goroutine会循环查看某个时效的文件是否存在，如果存在会继续查看该文件大小是否变化。
如果文件大小没有变化，则向主程序的通道发送一条消息。
如果循环超过一定次数，则会发送未找到的消息。&lt;/p&gt;
&lt;p&gt;主程序会循环从管道中接收消息，每读取一条消息，就会根据用户提供的命令模板生成对应时效的任务并执行。
如果接收到未找到文件的消息，程序则直接出错。&lt;/p&gt;
&lt;p&gt;为了降低系统负载，可以设置设置延迟启动时间，每次等待一定时间间隔后再开始检测下一时效。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;主程序创建一个通道，接收子程序发送的消息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CheckResult&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ForecastTime&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Duration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;FilePath&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ch&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; make(&lt;span style="color:#66d9ef"&gt;chan&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CheckResult&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;主程序为每个预报时效创建子程序，每个子程序会休眠指定时间再启动文件检测。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;oneTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;forecastTimeList&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;go&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;currentIndex&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;forecastTime&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Duration&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;sleepTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;delayTime&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Duration&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;currentIndex&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WithFields&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;forecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#a6e22e"&gt;Infof&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;sleeping before check...%v&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;sleepTime&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Sleep&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;sleepTime&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WithFields&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;forecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#a6e22e"&gt;Infof&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;checking begin...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;checkForOneTime&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ch&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;levels&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;forecastTime&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;checkDuration&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }(&lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;oneTime&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;主程序循环等待子程序发送的检查结果，如果找到文件则执行命令，如果没有找到文件则直接出错。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;range&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;forecastTimeList&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WithFields&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;: int(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ForecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#a6e22e"&gt;Fatalf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;check failed: %v&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WithFields&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;: int(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ForecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#a6e22e"&gt;Infof&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;file is available, run command...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;executeCommand&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;runCommand&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;commandTemplate&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;startTime&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ForecastTime&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;FilePath&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WithFields&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;: int(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ForecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#a6e22e"&gt;Fatalf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;run command failed: %v&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WithFields&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fields&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forecast_hour&amp;#34;&lt;/span&gt;: int(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ForecastTime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hours&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#a6e22e"&gt;Infof&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;run command success&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;程序源码参看&lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;nwpc-oper/nwpc-data-client&lt;/a&gt;&lt;/p&gt;</description></item><item><title>视界：专家探讨AI在地球系统应用中的使用</title><link>https://blog.perillaroc.wang/post/2019/2019-11-30-view-experts-probe-use-ai-earth-system-applications/</link><pubDate>Sat, 30 Nov 2019 15:38:29 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-11-30-view-experts-probe-use-ai-earth-system-applications/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自ECMWF官网中的新闻《&lt;a href="https://www.ecmwf.int/en/about/media-centre/news/2019/experts-probe-use-ai-earth-system-applications"&gt;Experts probe use of AI in Earth system applications&lt;/a&gt;》，版权归ECMWF所有。翻译底稿来自Google翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/styles/news_item_main_image/public/Martin-Palkovic-by-CV-690px.jpg?itok=IuTKTCbT"&gt;&lt;figcaption&gt;
			&lt;h4&gt;ECMWF计算主管MartinPalkovič主持了“哥白尼第一届人工智能研讨会”，并就ECMWF对大数据，人工智能和云计算的愿景进行了演讲。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;2019年11月5日至7日，六十九名科学家齐聚ECMWF，探讨在地球系统应用中扩大使用人工智能（AI）的范围。&lt;/p&gt;
&lt;p&gt;该活动由ECMWF实施的两项欧盟资助的哥白尼地球观测服务所组织：哥白尼大气监测服务（CAMS）和哥白尼气候变化服务（C3S）。&lt;/p&gt;
&lt;p&gt;活动的组织者之一，CAMS的负责人&lt;a href="https://www.ecmwf.int/en/about/who-we-are/staff-profiles/vincent-henri-peuch"&gt;Vincent Henri-Peuch&lt;/a&gt;说：“该研讨会取得了巨大的成功，提供了许多在地球科学及其他领域以不同形式使用AI的真实例子。研讨会证实了将AI应用与这一领域已经有了一定的成熟度。”&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-11/VHP-by-CV-690px.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;CAMS的主管Vincent-Henri Peuch是活动的组织者之一。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;28位发言者的报告表明，人工智能不仅在哥白尼，而且在ECMWF的数值天气预报核心任务中都有很大的用途。&lt;/p&gt;
&lt;p&gt;确实，是否所有的环境和天气预报都将由AI技术一天生成，而不是由当今基于物理的但计算成本很高的数值算法生成？&lt;/p&gt;
&lt;p&gt;对于正在ECMWF从事机器学习的&lt;a href="https://www.ecmwf.int/en/about/who-we-are/staff-profiles/peter-dueben"&gt;Peter Düben&lt;/a&gt;来说，这是一个悬而未决的问题。 他说：“使用神经网络预测天气状况的首次测试显示出令人鼓舞的结果，但仍有许多障碍需要克服。”&lt;/p&gt;
&lt;h3 id="什么是ai"&gt;什么是AI？&lt;/h3&gt;
&lt;p&gt;这场辩论中使用的一些关键术语是人工智能，机器学习和深度学习。&lt;/p&gt;
&lt;p&gt;人工智能广义上是指机器所展示的智能。&lt;/p&gt;
&lt;p&gt;在地球系统科学中正在探索的应用人工智能的形式包括机器学习（计算机不接收特定的指令，而是依靠模式和推理来执行任务）； 数据挖掘; 和数据融合。&lt;/p&gt;
&lt;p&gt;最后，深度学习是一种基于人工神经网络的机器学习形式。这样的网络的特征在于“隐藏层”的存在：算法的元素可以识别数据中的模式而无需进行显式编程。&lt;/p&gt;
&lt;p&gt;彼得说：“人工神经网络需要对输入和输出数据集进行训练，然后才能开始由新输入产生输出。”彼得在9月的第一周与牛津大学共同组织了&lt;a href="https://www.ecmwf.int/en/about/media-centre/science-blog/2019/will-machine-learning-replace-conventional-weather"&gt;一次机器学习研讨会，以进行天气和气候建模&lt;/a&gt;。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-11/Peter-Dueben-by-CV-690px.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;Peter Düben是研讨会的发言人之一。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="在哥白尼中使用ai"&gt;在哥白尼中使用AI&lt;/h3&gt;
&lt;p&gt;哥白尼地球观测计划已经以多种方式使用了AI。&lt;/p&gt;
&lt;p&gt;Vincent-Henri说：“例如，解释卫星图像，识别地球表面随时间的变化，以及将空气质量预测降尺度到更低的分辨率。”&lt;/p&gt;
&lt;p&gt;他强调，越来越多的用户对将AI应用于Copernicus数据感兴趣。 “我们需要预见这种需求并调整我们的数据，以使其易于在AI应用程序中使用。我们还必须研究在C3S气候数据存储和将来的CAMS大气数据存储中提供AI工具的情况。”&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-11/Pierre-Philippe-Mathieu-by-CV-690px.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;欧洲航天局（ESA）的Philippe-Pierre Mathieu发表了题为“用于地球观测的人工智能的兴起”的演讲。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Vincent-Henri认为，地球观测和天气预报可以借鉴其他科学领域的知识，例如高能物理学，这些领域在使用人工智能方面更为先进。&lt;/p&gt;
&lt;p&gt;“这就是为什么我们邀请来自不同领域的几位演讲者参加研讨会，他们能给我们带来对他们所在领域正在做的事情一些有趣的见解。”&lt;/p&gt;
&lt;h3 id="在天气预报中使用ai"&gt;在天气预报中使用AI&lt;/h3&gt;
&lt;p&gt;在数值天气预报中还有大量的机器学习用例，而如何充分利用AI技术是ECMWF以后研究的活跃领域。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-11/Samantha-Adams-by-CV-690px.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;英国气象局的Samantha Adams介绍了如何使用自组织映射来理解非线性云循环耦合。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;“潜在的使用领域包括数据质量控制；数据同化中的偏差校正；模拟模型组件；量化不确定性；还有更多，”Peter说。&lt;/p&gt;
&lt;p&gt;对于整个预报系统最终是否可以在AI上运行，而不是现在基于物理的算法运行，他显得比较谨慎。&lt;/p&gt;
&lt;p&gt;他说：“尽管我们有很多数据可以训练AI系统，但训练它们来预测整个地球系统及其所有复杂的相互作用可能还远远不够。”&lt;/p&gt;
&lt;p&gt;“最重要的是，我们生活在不断变化的气候中，发生了许多极端和前所未有的事件，人工智能可能会难以应对。”&lt;/p&gt;
&lt;p&gt;然而，在ECMWF上进行的实验表明，即使到今天，经过适当训练的神经网络也可以做出令人惊讶的准确性的短期预测。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-11/peter_dueben_merged-13-690px.jpg"&gt;
&lt;/figure&gt;

&lt;p&gt;该图显示了3月1日的世界标准时间和2017年3月2日的世界标准时间之间500 hPa（以m2 / s2为单位）的地势差，对比分析场（我们对当时的大气状态的最佳估计–左图）和从3月1日UTC 00开始的分析开始的24小时神经网络预测（右）。有关更多详细信息，请参见Geoscientific Model Development发表的&lt;a href="https://www.geosci-model-dev.net/11/3999/2018/"&gt;Peter Düben和Peter Bauer的文章&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Peter说：“毫无疑问，这是一个令人兴奋的研究领域，特别是因为当今许多高性能计算研究都针对AI应用。”&lt;/p&gt;
&lt;p&gt;“但是只有未来才能告诉我们，未来几十年和几十年后，在数值天气预报领域人工智能可以走多远。”&lt;/p&gt;
&lt;h3 id="下一步"&gt;下一步&lt;/h3&gt;
&lt;p&gt;研讨会的成果之一是意识到对于从事某些AI问题的科学家而言，缺少合适的训练数据集。&lt;/p&gt;</description></item><item><title>视界：ECMWF采用新的应用平台</title><link>https://blog.perillaroc.wang/post/2019/2019-11-16-view-ecmwf-adopts-new-application-platform/</link><pubDate>Sat, 16 Nov 2019 20:33:42 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-11-16-view-ecmwf-adopts-new-application-platform/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自ECMWF官网Newsletter Number 161 - Autumn 2019的文章《&lt;a href="https://www.ecmwf.int/en/newsletter/161/news/ecmwf-adopts-new-application-platform"&gt;ECMWF adopts new application platform&lt;/a&gt;》，版权归原作者Andrew Brady所有。翻译底稿来自Google翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;ECMWF开始使用部署在新IT平台上的应用程序提供部分Web和数据服务。
为了将ECMWF的数据中心迁移到博洛尼亚，我们正在转换多个应用程序，使其在Kubernetes管理的平台上作为Docker容器运行。
本文解释了什么是Docker/Kubernetes，为什么ECMWF正在越来越多地使用它们，以及这对用户意味着什么。&lt;/p&gt;
&lt;h3 id="变更原因"&gt;变更原因&lt;/h3&gt;
&lt;p&gt;从历史上讲，开发基于IT的应用程序意味着必须了解很多技术环境。
软件代码可以在有限的环境（例如笔记本电脑，台式机或工作站）中开发并完美运行，但是很难在其他环境中进行转换，维护和运行。
传统方法是基于共享代码和共享库开发服务和应用程序，这些代码和库部署在专用服务器上，以确保应用程序获得运行所需的IT环境和资源。
随着服务的增长，这种方法是不可持续的，并且无法在基础设施或工作量方面进行扩展。
在寻找替代方案时，ECMWF Web应用程序分析人员开始意识到两项新技术：Docker和Kubernetes。&lt;/p&gt;
&lt;h3 id="什么是docker和kubernetes"&gt;什么是Docker和Kubernetes&lt;/h3&gt;
&lt;p&gt;Docker是无需了解有关基础架构的详细信息而运行软件的通用环境。
Docker使用操作系统虚拟化技术，在称为容器的可运行程序包中一致地开发和交付软件应用程序。
Kubernetes是用于管理在基础设施集群上运行的Docker应用程序的工具。
Kubernetes解决了由容器组成的扩展和业务服务的问题。
业界已广泛采用Docker和Kubernetes开发应用程序，支持加速开发，产品快速迭代更新和有效扩展。它们是开发的关键技术。
ECMWF已跟进这些技术，并意识到它们对我们的服务是有益的。&lt;/p&gt;
&lt;h3 id="对于用户意味着什么"&gt;对于用户意味着什么&lt;/h3&gt;
&lt;p&gt;ECMWF当前已成功使用Docker和/或Kubernetes提供多种服务，包括Atlassian，EFAS-IS，GloFAS，RMDCN website，FTP，the Data Services Costing Application，Accounts和Nexus。
还计划在博洛尼亚的Kubernetes上部署其他服务，包括 &lt;a href="//www.ecmwf.int"&gt;www.ecmwf.int&lt;/a&gt; 网站，ecCharts和webapi。&lt;/p&gt;
&lt;p&gt;ECMWF采用Docker和Kubernetes后，这些服务的用户应该看到的主要改进包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缩短了修复/更新/改进的周转时间&lt;/li&gt;
&lt;li&gt;因为在开发过程中对应用程序进行了更全面的测试而提供的更加强大的服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如图所示，因为开发可以相对独立地进行，使用 Docker/Kubernetes 还可以改善我们的工作流程。
另外，由于无需为业务运行而更改应用程序容器，因此有利于应用程序到生产的过渡。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://www.ecmwf.int/sites/default/files/medialibrary/2019-10/NL_161_-_News_4_-_Brady_-_Figure_1_vc.svg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;持续集成工作流程示例。此处显示的工作流程使开发人员能够安全地隔离代码变更并在自己的桌面上测试自己的工作。当他们满意时，可以提交变更，这将触发生成Docker容器的工作流程，如果成功，将自动部署。然后，就可以作为通常可访问的测试服务使用。如果测试人员满意，则服务操作奇偶手动触发对生产环境的更新，可能会在计划任务中实现。从源代码变更到部署再到生产环境，整个工作流程都是可追溯的。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="当前的设置"&gt;当前的设置&lt;/h3&gt;
&lt;p&gt;我们当前的Kubernetes群集由来自VMWARE VSPHERE和Network Attached Storage的虚拟机（VM）组成，以实现数据持久性。
通过使用Kubernetes添加新的VM和/或更大的VM来跨VM编排容器，可以透明地扩展基础架构。
在生产环境中，该群集默认情况下还提供许多可运行的功能，使用该群集可大大减少实施生产应用程序组件（例如Web服务器，应用程序服务器或数据库）所需的工作量。&lt;/p&gt;
&lt;p&gt;重要的是要认识到Docker和Kubernetes并不是我们唯一使用的技术。
为了有效、稳健地部署应用程序，我们使用持续集成/持续部署（CI/CD）工具。
我们使用&lt;a href="https://www.atlassian.com/software/bitbucket"&gt;Atlassian Bitbucket&lt;/a&gt;，&lt;a href="https://goharbor.io/"&gt;Harbour&lt;/a&gt;，&lt;a href="https://www.sonatype.com/product-nexus-repository"&gt;Nexus&lt;/a&gt;和&lt;a href="https://www.atlassian.com/software/bamboo"&gt;Atlassian BAMBOO&lt;/a&gt;。
有了这些工具，我们便拥有了一个流水线系统，该系统可实现轻而易举的快速，稳健的开发，直至运营。
我们还集成了自动化功能，以测试并确保代码质量和基础平台的安全性。&lt;/p&gt;
&lt;p&gt;如果您有兴趣了解更多信息，请随时与Andrew Brady（&lt;a href="mailto:andrew.brady@ecmwf.int"&gt;andrew.brady@ecmwf.int&lt;/a&gt;）联系。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;ECMWF 每个季度的 Newsletter 一般都会有一篇文章与信息化相关。
八月份的正好有一篇介绍我一直想引入到工作环境中却始终缺乏进展的容器技术。&lt;/p&gt;</description></item><item><title>视界：机器学习会替代现有的天气预报模式么？</title><link>https://blog.perillaroc.wang/post/2019/2019-11-16-view-will-machine-learning-replace-conventional-weather-prediction-models/</link><pubDate>Sat, 16 Nov 2019 13:27:32 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-11-16-view-will-machine-learning-replace-conventional-weather-prediction-models/</guid><description>&lt;h2 id="声明"&gt;声明&lt;/h2&gt;
&lt;p&gt;本文正文内容翻译自ECMWF官网中&lt;a href="https://www.ecmwf.int/en/about/who-we-are/staff-profiles/peter-dueben"&gt;Peter Dueben&lt;/a&gt;的文章《&lt;a href="https://www.ecmwf.int/en/about/media-centre/science-blog/2019/will-machine-learning-replace-conventional-weather"&gt;Will machine learning replace conventional weather prediction models?&lt;/a&gt;》，版权归原作者所有。翻译底稿来自Google翻译。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文&lt;/h2&gt;
&lt;p&gt;作者是研讨会&lt;a href="http://users.ox.ac.uk/~phys0895/mlwc2019/index.html"&gt;Machine Learning for Weather and Climate Modelling&lt;/a&gt;的组织者之一。该研讨会于9月第一周在牛津的 Corpus Christi College 召开。为期四天的 workshop 讨论未来如何使用机器学习技术来改善天气和和气候模式。&lt;/p&gt;
&lt;h3 id="什么是机器学习"&gt;什么是机器学习&lt;/h3&gt;
&lt;p&gt;一般来说，机器学习工具用于开发计算机模型，能够从大量“输入”和“输出”数据对中表示一个复杂的“系统”。
“系统”可能是一个观察一幅图片（输入）并理解图片的内容（输出）的人；可能是一个考虑棋盘上所有棋子位置（输入）并决定下一步（输出）的棋手；或者一名估算自行车位置和速度（输入）并决定是否超车（输出）的司机
如果有足够数量的输入/输出对用于训练，及其学习可以用来开发数值工具，用来模仿由相当复杂的系统所作的决策。&lt;/p&gt;
&lt;h3 id="机器学习该如何用到数值天气预报中"&gt;机器学习该如何用到数值天气预报中&lt;/h3&gt;
&lt;p&gt;在数值天气预报的整个流程中，机器学习由很多潜在的应用领域。
在这里，“系统”可以是一种在数据同化过程中选择和纠正观测数据的工具；
可以是一种用于将显示世界中观测数据投影到模式中可以使用的变量；
或者是数值预报模式的一部分——例如给定表面温度、云形状和太阳辐射条件下预测大气热效应的辐射方案。
也可以是一种用于天气预报模式输出数据后处理的工具，例如在预报结果中发现极端天气事件或者对特定位置的预报进行偏差订正。&lt;/p&gt;
&lt;p&gt;实际上，研讨会的报告涵盖了天气和气候模式工作流中的许多应用领域。
了解哪些已经成功使用机器学习工具的领域，以及那些需要更多工作才能使及其学习变得与常规模式一样好的领域，的确令人鼓舞。&lt;/p&gt;
&lt;p&gt;使用机器学习对于在天气和气候模式并不是全新的方法。
可以说机器学习已经成为许多研究领域的标准方法，例如计算两个预报变量的相关性。
也可以说，数据同化过程（在ECMWF中用于生成数值天气预报的初始场）可以被视为机器学习应用。
但是，新工具的开发（例如具有大量自由度的深度神经网络）使我们能够使用比传统应用领域复杂得多的机器学习系统。
此外，借助现在的计算基础架构，我们可以存储并处理更多的输入输出数据对，这使得机器学习工具比过去更加强大。&lt;/p&gt;
&lt;p&gt;实际上，机器学习在很大程度上影响着未来超级计算机的发展。
这意味着天气和气候模式社区将需要在不久的将来学习如何有效利用针对特定应用优化的硬件（需要以非常低的数值精度使用密集线性代数）。&lt;/p&gt;
&lt;h3 id="进展和挑战"&gt;进展和挑战&lt;/h3&gt;
&lt;p&gt;在研讨会上，来自世界各地的100多位科学家通过讲座，海报展示和分组讨论，讨论了天气和气候模式中机器学习的进展和挑战。
研讨会汇集了来自气象和地球科学，计算，应用数学和统计学的研究人员，以及来自大学，天气和气候研究中心以及行业的科学家。
ECMWF的四名工作人员参加了研讨会，并进行了三场演讲。&lt;/p&gt;
&lt;p&gt;这些贡献再次表明，机器学习非常强大，并且机器学习应用的范围在过去几年中已显著增加。
实际上，由于研究进展惊人，目前很难及时了解最新动态，这正是研讨会如此重要和及时的原因之一。&lt;/p&gt;
&lt;p&gt;在研讨会期间，我们还讨论了天气和气候模式领域使用机器学习工具时遇到的许多挑战，这些挑战需要社区解决。
例如，很难利用有关物理系统的现有知识来改进机器学习工具，因为此类工具会从数据中学习并作为一个“黑匣子”应用使用。
因此，这些工具很难表现出保护性，如果使用新的输入（训练过程中未使用的数据集），则存在数据训练的模型失败的风险。
在超级计算机上运行时，将机器学习软件与传统模型链接起来也具有挑战性。&lt;/p&gt;
&lt;p&gt;机器学习工具学习的“系统”也可能是现实世界中的“天气”。
该工具将使用特定时间的大气状态（输入）来预测稍后时间的状态（输出）。
一旦经过训练，这种工具就可以用来预测未来，并可以与传统天气预报模式相同的方式实际产生天气预报。
研讨会上有一些贡献试图做到这一点（包括作者自己的&lt;a href="https://www.geosci-model-dev.net/11/3999/2018/"&gt;论文&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;机器学习在数值天气预报中的所有可能应用中，可以将这一应用视为最具挑战性的应用。
到研讨会结束时，在回顾并讨论了各种各样的可能性和之后，与会人员之间仍未就这种机器学习模型是否能够在将来的某个时候击败传统的天气预报模式达成共识。
意见范围从：“肯定是”到“我会赌我的房子反对”。作者尚不知道这是否将成为可能，它当然需要在天气和气候科学以及深度学习和计算机科学领域进行很多非常具有挑战性（因此很有趣）的研究。
作者期待贡献！&lt;/p&gt;
&lt;h3 id="致谢"&gt;致谢&lt;/h3&gt;
&lt;p&gt;研讨会的科学组织由Matthew Chantry，Hannah Christensen，ECMWF研究员Tim Palmer（均来自牛津大学）和作者本人完成。
我们已经从Philippa Towler那里获得了对整个组织的重要支持。
这次会议之所以成为可能，要归功于亚马逊， the Copernicus Atmosphere Monitoring Service（CAMS），the Copernicus Climate Change Service （C3S），ESiWACE Centre of Excellence，NVIDIA ，the Office of Naval Research 和 Vulcan 的财务支持。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - 位图</title><link>https://blog.perillaroc.wang/post/2019/2019-11-11-grib-notebook-learn-by-sample-bitmap/</link><pubDate>Mon, 11 Nov 2019 22:06:05 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-11-11-grib-notebook-learn-by-sample-bitmap/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍使用Section 6位图段的GRIB2数据。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;某些数据可能有缺失值，我们一般使用一个比较大的值代表缺失，如果将该值保存到数据中，会导致存储空间浪费。&lt;/p&gt;
&lt;p&gt;Section 6位图段用于处理这种情况，位图段使用1个位表示网格点对应的数据是否保存到数据段中。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1：数据保存&lt;/li&gt;
&lt;li&gt;0：数据不保存&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;相比于数据段每个数据使用10个bits保存，位图段使用1个bit表示数据缺失能有效减少存储空间。&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年11月4日00时次003时效的反照率（Albedo (%) ）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;***** FILE: bitmap.grib2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#============== MESSAGE 1 ( length=600630 ) ==============
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 identifier = GRIB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5-6 reserved = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7 discipline = 0 [Meteorological products (grib2/tables/4/0.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8 editionNumber = 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;9-16 totalLength = 600630
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_1 ( length=21, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section1Length = 21
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-7 centre = 38 [Beijing (RSMC) (common/c-11.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8-9 subCentre = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10 tablesVersion = 4 [Version implemented on 7 November 2007 (grib2/tables/1.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 localTablesVersion = 1 [Unknown code table entry (grib2/tables/4/1.1.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12 significanceOfReferenceTime = 1 [Start of forecast (grib2/tables/4/1.2.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13-14 year = 2019
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;15 month = 11
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16 day = 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;17 hour = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;18 minute = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;19 second = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;20 productionStatusOfProcessedData = 0 [Operational products (grib2/tables/4/1.3.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;21 typeOfProcessedData = 1 [Forecast products (grib2/tables/4/1.4.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_3 ( length=72, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section3Length = 72
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6 sourceOfGridDefinition = 0 [Specified in Code table 3.1 (grib2/tables/4/3.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7-10 numberOfDataPoints = 1036800
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 numberOfOctectsForNumberOfPoints = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12 interpretationOfNumberOfPoints = 0 [There is no appended list (grib2/tables/4/3.11.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13-14 gridDefinitionTemplateNumber = 0 [Latitude/longitude (Also called equidistant cylindrical, or Plate Carree) (grib2/tables/4/3.1.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;15 shapeOfTheEarth = 6 [Earth assumed spherical with radius of 6,371,229.0 m (grib2/tables/4/3.2.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16 scaleFactorOfRadiusOfSphericalEarth = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;17-20 scaledValueOfRadiusOfSphericalEarth = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;21 scaleFactorOfEarthMajorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;22-25 scaledValueOfEarthMajorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;26 scaleFactorOfEarthMinorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;27-30 scaledValueOfEarthMinorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;31-34 Ni = 1440
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;35-38 Nj = 720
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;39-42 basicAngleOfTheInitialProductionDomain = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;43-46 subdivisionsOfBasicAngle = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;47-50 latitudeOfFirstGridPoint = 89875000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;51-54 longitudeOfFirstGridPoint = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;55 resolutionAndComponentFlags = 48 [00110000]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;56-59 latitudeOfLastGridPoint = -89875000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;60-63 longitudeOfLastGridPoint = 359750000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;64-67 iDirectionIncrement = 250000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;68-71 jDirectionIncrement = 250000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;72 scanningMode = 0 [00000000]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_4 ( length=34, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section4Length = 34
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-7 NV = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8-9 productDefinitionTemplateNumber = 0 [Analysis or forecast at a horizontal level or in a horizontal layer at a point in time (grib2/tables/4/4.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10 parameterCategory = 19 [Physical atmospheric properties (grib2/tables/4/4.1.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 parameterNumber = 1 [Albedo (%) (grib2/tables/4/4.2.0.19.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12 typeOfGeneratingProcess = 2 [Forecast (grib2/tables/4/4.3.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13 backgroundProcess = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;14 generatingProcessIdentifier = 15
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;15-16 hoursAfterDataCutoff = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;17 minutesAfterDataCutoff = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;18 indicatorOfUnitOfTimeRange = 1 [Hour (grib2/tables/4/4.4.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;19-22 forecastTime = 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;23 typeOfFirstFixedSurface = 1 [Ground or water surface (grib2/tables/4/4.5.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;24 scaleFactorOfFirstFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;25-28 scaledValueOfFirstFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;29 typeOfSecondFixedSurface = 255 [Missing (grib2/tables/4/4.5.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;30 scaleFactorOfSecondFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;31-34 scaledValueOfSecondFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_5 ( length=23, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section5Length = 23
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-9 numberOfValues = 500443
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10-11 dataRepresentationTemplateNumber = 40 [JPEG2000 Packing (grib2/tables/4/5.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12-15 referenceValue = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16-17 binaryScaleFactor = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;18-19 decimalScaleFactor = 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;20 bitsPerValue = 13
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;21 typeOfOriginalFieldValues = 0 [Floating point (grib2/tables/4/5.1.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;22 typeOfCompressionUsed = 0 [Lossless (grib2/tables/4/5.40.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;23 targetCompressionRatio = 255
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_6 ( length=129606, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section6Length = 129606
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6 bitMapIndicator = 0 [A bit map applies to this product and is specified in this Section (grib2/tables/4/6.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7-129606 bitmap = 129600 {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 00, 00, 00, 00
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ... 129500 more values
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } # g2bitmap bitmap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_7 ( length=470854, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section7Length = 470854
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-470854 codedValues = (500443,470849) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.0000000000e+00, 0.0000000000e+00, 0.0000000000e+00, 0.0000000000e+00, 0.0000000000e+00, 6.7470000000e+01, 6.7540000000e+01, 6.7490000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.7770000000e+01, 6.7430000000e+01, 6.7830000000e+01, 6.7520000000e+01, 6.7510000000e+01, 6.7660000000e+01, 6.7370000000e+01, 6.7340000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.7480000000e+01, 6.7840000000e+01, 6.7880000000e+01, 6.7950000000e+01, 6.7780000000e+01, 6.7830000000e+01, 6.8030000000e+01, 6.7880000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.8100000000e+01, 6.7840000000e+01, 6.8080000000e+01, 6.8210000000e+01, 6.8120000000e+01, 6.7930000000e+01, 6.8020000000e+01, 6.7980000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.8030000000e+01, 6.8120000000e+01, 6.8310000000e+01, 6.8560000000e+01, 6.8580000000e+01, 6.8910000000e+01, 6.9460000000e+01, 6.9690000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.9490000000e+01, 6.9620000000e+01, 6.9990000000e+01, 7.0100000000e+01, 6.9940000000e+01, 6.9690000000e+01, 6.9950000000e+01, 7.0270000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7.0030000000e+01, 6.9880000000e+01, 7.0100000000e+01, 7.0410000000e+01, 7.0100000000e+01, 6.9570000000e+01, 6.9340000000e+01, 0.0000000000e+00,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0.0000000000e+00, 0.0000000000e+00, 0.0000000000e+00, 0.0000000000e+00, 6.8140000000e+01, 6.7800000000e+01, 6.7810000000e+01, 6.8310000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.8290000000e+01, 6.7820000000e+01, 6.7490000000e+01, 6.7660000000e+01, 6.7420000000e+01, 6.7890000000e+01, 6.7000000000e+01, 6.6680000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.6530000000e+01, 6.6570000000e+01, 6.6720000000e+01, 6.6640000000e+01, 6.6740000000e+01, 6.6920000000e+01, 6.7200000000e+01, 6.7360000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.7330000000e+01, 6.7080000000e+01, 6.7630000000e+01, 6.7650000000e+01, 6.7560000000e+01, 6.7320000000e+01, 6.7390000000e+01, 6.7350000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.7360000000e+01, 6.7570000000e+01, 6.7660000000e+01, 6.7640000000e+01, 6.7800000000e+01, 6.7600000000e+01, 6.7900000000e+01, 6.7870000000e+01,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6.7940000000e+01, 6.7820000000e+01, 6.7950000000e+01, 6.8540000000e+01
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;... 500343 more values
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} # data_jpeg2000_packing codedValues
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_8 ( length=4, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 7777 = 7777
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述&lt;code&gt;grib_dump&lt;/code&gt;的输出可以看到，Section 6中的bitMapIndicator被设置为0，表示使用位图段。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - 常量要素场</title><link>https://blog.perillaroc.wang/post/2019/2019-11-09-grib-notebook-learn-by-sample-constant-field/</link><pubDate>Sat, 09 Nov 2019 20:47:29 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-11-09-grib-notebook-learn-by-sample-constant-field/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍所有数值都相等的常量要素场。&lt;/p&gt;
&lt;h2 id="常量要素场constant-field"&gt;常量要素场（Constant Field）&lt;/h2&gt;
&lt;p&gt;如果某个要素场的所有数值都是同一个值，那么仅需要保存一个数值就能代表整个要素场。
虽然GRIB2使用的JPEG 2000压缩算法会考虑重复出现的数值，但如果我们只保存一个数值，就能避免对数据进行压缩和解压缩，也能节省一部分空间。&lt;/p&gt;
&lt;p&gt;所以，ecCodes在处理常量要素场时，仅使用referenceValue保存数据。&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年8月17日00时次000时效的净长波辐射（Net long wave radiation flux (W m-2)）。&lt;/p&gt;
&lt;p&gt;grib_dump的输出如下所示&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;***** FILE: constant_field.grib2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;#============== MESSAGE 1 ( length=205 ) ==============
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 identifier = GRIB
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5-6 reserved = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7 discipline = 0 [Meteorological products (grib2/tables/4/0.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8 editionNumber = 2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;9-16 totalLength = 205
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_1 ( length=21, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section1Length = 21
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-7 centre = 38 [Beijing (RSMC) (common/c-11.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8-9 subCentre = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10 tablesVersion = 4 [Version implemented on 7 November 2007 (grib2/tables/1.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 localTablesVersion = 1 [Unknown code table entry (grib2/tables/4/1.1.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12 significanceOfReferenceTime = 0 [Analysis (grib2/tables/4/1.2.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13-14 year = 2019
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;15 month = 8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16 day = 7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;17 hour = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;18 minute = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;19 second = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;20 productionStatusOfProcessedData = 0 [Operational products (grib2/tables/4/1.3.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;21 typeOfProcessedData = 0 [Analysis products (grib2/tables/4/1.4.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_3 ( length=72, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section3Length = 72
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 3
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6 sourceOfGridDefinition = 0 [Specified in Code table 3.1 (grib2/tables/4/3.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;7-10 numberOfDataPoints = 1036800
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 numberOfOctectsForNumberOfPoints = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12 interpretationOfNumberOfPoints = 0 [There is no appended list (grib2/tables/4/3.11.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13-14 gridDefinitionTemplateNumber = 0 [Latitude/longitude (Also called equidistant cylindrical, or Plate Carree) (grib2/tables/4/3.1.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;15 shapeOfTheEarth = 6 [Earth assumed spherical with radius of 6,371,229.0 m (grib2/tables/4/3.2.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16 scaleFactorOfRadiusOfSphericalEarth = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;17-20 scaledValueOfRadiusOfSphericalEarth = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;21 scaleFactorOfEarthMajorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;22-25 scaledValueOfEarthMajorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;26 scaleFactorOfEarthMinorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;27-30 scaledValueOfEarthMinorAxis = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;31-34 Ni = 1440
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;35-38 Nj = 720
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;39-42 basicAngleOfTheInitialProductionDomain = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;43-46 subdivisionsOfBasicAngle = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;47-50 latitudeOfFirstGridPoint = 89875000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;51-54 longitudeOfFirstGridPoint = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;55 resolutionAndComponentFlags = 48 [00110000]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;56-59 latitudeOfLastGridPoint = -89875000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;60-63 longitudeOfLastGridPoint = 359750000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;64-67 iDirectionIncrement = 250000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;68-71 jDirectionIncrement = 250000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;72 scanningMode = 0 [00000000]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_4 ( length=58, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section4Length = 58
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 4
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-7 NV = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;8-9 productDefinitionTemplateNumber = 8 [Average, accumulation, extreme values or other statistically processed values at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval (grib2/tables/4/4.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10 parameterCategory = 5 [Long-wave Radiation (grib2/tables/4/4.1.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11 parameterNumber = 5 [Net long wave radiation flux (W m-2) (grib2/tables/4/4.2.0.5.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12 typeOfGeneratingProcess = 0 [Analysis (grib2/tables/4/4.3.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13 backgroundProcess = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;14 generatingProcessIdentifier = 15
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;15-16 hoursAfterDataCutoff = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;17 minutesAfterDataCutoff = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;18 indicatorOfUnitOfTimeRange = 1 [Hour (grib2/tables/4/4.4.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;19-22 forecastTime = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;23 typeOfFirstFixedSurface = 1 [Ground or water surface (grib2/tables/4/4.5.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;24 scaleFactorOfFirstFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;25-28 scaledValueOfFirstFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;29 typeOfSecondFixedSurface = 255 [Missing (grib2/tables/4/4.5.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;30 scaleFactorOfSecondFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;31-34 scaledValueOfSecondFixedSurface = MISSING
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;35-36 yearOfEndOfOverallTimeInterval = 2019
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;37 monthOfEndOfOverallTimeInterval = 8
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;38 dayOfEndOfOverallTimeInterval = 7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;39 hourOfEndOfOverallTimeInterval = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;40 minuteOfEndOfOverallTimeInterval = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;41 secondOfEndOfOverallTimeInterval = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;42 numberOfTimeRange = 1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;43-46 numberOfMissingInStatisticalProcess = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;47 typeOfStatisticalProcessing = 1 [Accumulation (grib2/tables/4/4.10.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;48 typeOfTimeIncrement = 2 [Successive times processed have same start time of forecast, forecast time is incremented (grib2/tables/4/4.11.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;49 indicatorOfUnitForTimeRange = 1 [Hour (grib2/tables/4/4.4.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;50-53 lengthOfTimeRange = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;54 indicatorOfUnitForTimeIncrement = 255 [Missing (grib2/tables/4/4.4.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;55-58 timeIncrement = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_5 ( length=23, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section5Length = 23
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6-9 numberOfValues = 1036800
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;10-11 dataRepresentationTemplateNumber = 40 [JPEG2000 Packing (grib2/tables/4/5.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;12-15 referenceValue = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16-17 binaryScaleFactor = -10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;18-19 decimalScaleFactor = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;20 bitsPerValue = 0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;21 typeOfOriginalFieldValues = 0 [Floating point (grib2/tables/4/5.1.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;22 typeOfCompressionUsed = 0 [Lossless (grib2/tables/4/5.40.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;23 targetCompressionRatio = 255
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_6 ( length=6, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section6Length = 6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 6
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;6 bitMapIndicator = 255 [A bit map does not apply to this product (grib2/tables/4/6.0.table) ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_7 ( length=5, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 section7Length = 5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;5 numberOfSection = 7
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;====================== SECTION_8 ( length=4, padding=0 ) ======================
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1-4 7777 = 7777
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过上面的dump文本可以看到，常量要素场的Section 7只有5个字节，没有数据内容。&lt;/p&gt;</description></item><item><title>大气科学基础知识培训班结业</title><link>https://blog.perillaroc.wang/post/2019/2019-11-02-atmospheric-basic-knowledge-training-course/</link><pubDate>Sat, 02 Nov 2019 11:30:06 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-11-02-atmospheric-basic-knowledge-training-course/</guid><description>&lt;p&gt;经过一个月的学习，终于完成了大气基础知识培训班的所有课程和考核，还幸运地拿到优秀学员的证书（占比40%左右）。这次培训班收获颇丰，不仅学到了大气科学的基础知识，还与来自天南海北的同事们一起学习交流，分享各自的工作经验。去气象局大院和海淀区气象局参观也深有体会，感觉现在各个单位的飞速发展，也看到了目前我们部门存在的问题。正如我在结业汇报的最后说的，无论我以后从事什么样的岗位，我相信这次培训都会给我未来的工作带来很大的帮助。&lt;/p&gt;
&lt;h2 id="缘起"&gt;缘起&lt;/h2&gt;
&lt;p&gt;我从2013年参加工作开始就一直想参见大气科学基础知识培训班。在2014年新员工的座谈会中还提到我们单位应该对非气象专业的新员工进行类似的培训。不知道是不是因为我提了这一点，2014年入职的新员工就参加了当年3个月的培训。不过，后面几年我们数值预报中心没有非气象专业的新员工，我就不知道新员工是否还会参加了。&lt;/p&gt;
&lt;p&gt;这几年一直都没有找到机会参加，因为鉴于我们科目前的人力状况和平时工作的特点，三个月的脱产学习绝对不会被领导同意。幸运的是，今年干部学院将三个月的面授课程改为一个月的面授加上在线学习。我也就马上抓住这次机会，申请参加今年的基础班学习。这是参加工作六年来第一次申请通过的培训。上一次申请去ecmwf学习没有被领导同意后就看清了运行科所处的地位，所以对参加国外培训一直没有兴趣。不过，国内的培训我以后还是要多关注下，同时也应该如同学在结业汇报中提到的那样，建议科内的同事多参加类似的培训。&lt;/p&gt;
&lt;p&gt;参加培训还有一个小插曲。本来我应该是9月份参加第一期的面授，结果我当时忘了时间，没去报名，第一天也没去上课。后两天经过多方协商，最终改为参加10月份的第五期。我之前对自己的某些事情不太上心，才导致这样的结果。不过好在我还是在10月份按时上课了，晚了一个月对于本身就住在气象局大院里的我来说影响不大。另外，秋天晚上黑的时间早，不太适合带孩子下楼玩，10月份比9月份晚半个小时下课也就无所谓了。&lt;/p&gt;
&lt;h2 id="课程"&gt;课程&lt;/h2&gt;
&lt;p&gt;按照新的培训安排，基础班学员应该在线学习绝大部分的内容，面授是对在线课程的深入。可惜因为个人和工作上的原因，我几乎没有学习在线课程，大部分同学的情况与我类似。老师授课的时间比原来三个月大幅度缩减，所以上课显得时间比较紧张，只能科普性质的介绍。不过即便我没有认真完成在线课程，线下授课也让我学到了很多的知识，进一步加深对大气科学的认识，为以后的工作也打下了坚实的基础。培训仅仅是一个开始，想要做好业务工作，需要持续学习气象业务相关知识，想要做好科研工作，也需要深入学习大气科学相关知识。正如同学在总结中提到，本次培训激发了持续学习气象知识的动力。&lt;/p&gt;
&lt;p&gt;本次培训的课程分为四个部分，下面分别介绍下。&lt;/p&gt;
&lt;h3 id="理论精讲"&gt;理论精讲&lt;/h3&gt;
&lt;p&gt;理论精讲是对在线授课的深入讲解。因为大家在线学习效果基本没有达到预期，所以精讲变成了科普。&lt;/p&gt;
&lt;p&gt;精讲课程包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大气科学概论&lt;/li&gt;
&lt;li&gt;大气探测学（包括卫星气象观测）&lt;/li&gt;
&lt;li&gt;天气学（天气学原理、天气分析）&lt;/li&gt;
&lt;li&gt;气候学&lt;/li&gt;
&lt;li&gt;动力气象学概论&lt;/li&gt;
&lt;li&gt;数值预报概论&lt;/li&gt;
&lt;li&gt;应用气象学（农业气象）&lt;/li&gt;
&lt;li&gt;公共气象服务&lt;/li&gt;
&lt;li&gt;气象统计&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;全面涵盖观测、预报和服务等所有气象业务领域。不过，因为授课时长的原因，所有课程都没法深入展开，有些课程只有短短的一个半小时时间。想要学习更多的知识，还得靠个人的持续努力。&lt;/p&gt;
&lt;h3 id="理论应用"&gt;理论应用&lt;/h3&gt;
&lt;p&gt;理论应用偏向于案例讨论，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;气象为农服务案例&lt;/li&gt;
&lt;li&gt;党性教育案例&lt;/li&gt;
&lt;li&gt;气象公共服务案例&lt;/li&gt;
&lt;li&gt;风险管理案例&lt;/li&gt;
&lt;li&gt;气象与社会&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;案例教学采用分组讨论的形式，大家各抒观点，并推选一人进行最终的汇报。这样的形式最能体现个人的特色，能从同学们的不同思考方式中学到很多东西。&lt;/p&gt;
&lt;h3 id="特色讲座"&gt;特色讲座&lt;/h3&gt;
&lt;p&gt;特色讲座邀请了各位专家对气象历史和现在的发展进行了深入的讲解，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;气象科技史&lt;/li&gt;
&lt;li&gt;天气预报业务进展&lt;/li&gt;
&lt;li&gt;ENSO机理&lt;/li&gt;
&lt;li&gt;雷达应用与强对流预报&lt;/li&gt;
&lt;li&gt;气象卫星进展&lt;/li&gt;
&lt;li&gt;智能气象预报业务&lt;/li&gt;
&lt;li&gt;生态气象业务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特色讲座最有意思的就是预报司黄卓副司长在介绍智能气象预报时，前半部分重点提到数值天气预报，并说今年气象局会对数值预报的布局进行重新设计。既然都已经公开说了，说明改革的方案定得差不多了。还剩下两个月，谜底总会揭晓。&lt;/p&gt;
&lt;h3 id="现场教学"&gt;现场教学&lt;/h3&gt;
&lt;p&gt;现场教学包括参观和体育课：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;气象局大院&lt;/li&gt;
&lt;li&gt;海淀区气象局&lt;/li&gt;
&lt;li&gt;西山革命基地&lt;/li&gt;
&lt;li&gt;体育课&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参观气象局大院和海淀区气象局之前的文章已经介绍，请参看《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-16-visiting-china-meteorological-administration/"&gt;参观中国气象局大院有感&lt;/a&gt;》和《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-29-visitiong-haidian-district-meteorology-bureau/"&gt;参观北京市海淀区气象局有感&lt;/a&gt;》。&lt;/p&gt;
&lt;h2 id="座谈与汇报"&gt;座谈与汇报&lt;/h2&gt;
&lt;p&gt;上课期间针对授课形式进行了一次座谈，并在课程最后进行了个人学习汇报。&lt;/p&gt;
&lt;h3 id="座谈会"&gt;座谈会&lt;/h3&gt;
&lt;p&gt;座谈会发言需要回答下面5个问题，下面我将问题和发言稿一并列出。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网络学习的收获（学得怎么样？）、体会（难易、重复多少遍能学懂？）和建议&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;刚开放网课的时候，利用上班时间看了几个学时。但发现上班期间工作任务太多，就没有继续后续课时。因为一开始只有两门课，总觉得后面还有时间学习。很长时间之后，当我再一次登录网站时，发现突然多出来这么多课。估算了下剩下的时间和剩余的课时数，发现即便我白天8个小时都在学习，也不够完成整个的学时。然后就没有再认真学习，只是挂在电脑上播放。&lt;/p&gt;
&lt;p&gt;我建议可以参考Coursera等成熟的在线学习网站，为每节课指定一个更详细的学习计划，比如每门课需要学习几周，每周需要投入多少时间来学习。将授课视频分割成更小的单元，便于利用上班空余时间来持续学习。当然不同课程可能有不同的特点，无法一概而论。
我还建议提供一个更宽泛灵活的在线学习时间，将学习目标从侧重所有课时改为侧重逐渐完成各个科目。比如可以分不同时间段放出各个课程，让大家在同一的时间段只学习一到两个课程。这样更有利于找到时间完成课程目标。当然，这样会导致整个课程在线学习的延长，比如完成所有课程目标可能会持续一年时间。但对于非气象专业毕业的气象人来讲，我们学习气象知识往往是为了更好地了解自己的工作，更好地融入整个气象行业，对学习的时效性要求不高。所以我觉得可以通过延长在线学习时间来降低学习负担。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网络学习的效果检验与考核方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们网课的考核是通过在线完成问答题的形式。非常适合对整个课程学习效果的考核。与刚才我提到的一样，如果更侧重单个科目的话，建议每个科目单独考核，将考核分散到整个的学习过程中。&lt;/p&gt;
&lt;p&gt;另外，建议参考Coursera等的课程作业方式。可以在视频播放中间附加简单的选择题，确保听众理解课程内容；在每周的课程结束时进行小测验，方便学员检验自己本周的学习成果，如果只用单向选择题，则可以做成自动测试。某些课程可以增加一些开放式的作业，引入同学间互评，提高学习参与度。这些建议的前提是要显著延长整个学习的时间跨度，否则会给学员带来过多的负担。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;日常网络学习中，每周可以投入多少时间（小时）学习培训课程？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最佳情况下，可以投入2*7=14小时左右，即平均每天2小时，一周总共14小时。因为工作日只有晚上才有空闲时间，周末无法投入更多的时间，所以平均一天只有2个小时。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;是否参加过在线答疑？如参加过，谈谈体会和建议。如未参加过，原因？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;没有参加过在线答疑。因为没有按时上课。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对面授培训的意见和建议&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;非常珍惜有面授的机会，对于像我从事的工作岗位来说，很难有像这样与来自天南海北从事不同岗位的同行进行思想碰撞的机会。当然我也很珍惜各位老师的精彩授课，即便我因为种种原因没有认真学习线上课程，我也从课程中学到了很多知识，对以后的工作也有很大的帮助。所以我建议无论在线课程如何变革，依然要保留线下授课。&lt;/p&gt;
&lt;h3 id="学习汇报"&gt;学习汇报&lt;/h3&gt;
&lt;p&gt;学习汇报PPT需要包含下面4项内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从事的是什么工作（岗位），平时工作中需要了解哪些气象知识？&lt;/li&gt;
&lt;li&gt;目前工作中还欠缺哪些气象知识，造成了什么不利影响（举例说明）？&lt;/li&gt;
&lt;li&gt;通过网络学习或者面授学习，现在学到了哪些与岗位密切相关的气象知识？&lt;/li&gt;
&lt;li&gt;学到的知识对未来工作开展有什么帮助（举例说明）？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我的汇报内容会在另一篇文章中介绍。&lt;/p&gt;</description></item><item><title>参观北京市海淀区气象局有感</title><link>https://blog.perillaroc.wang/post/2019/2019-10-29-visitiong-haidian-district-meteorology-bureau/</link><pubDate>Tue, 29 Oct 2019 21:36:24 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-29-visitiong-haidian-district-meteorology-bureau/</guid><description>&lt;p&gt;10月22日下午，与参加大气科学基础知识班的同学一同参观位于海淀公园旁边的海淀区气象局。
上一次参观北京市的气象系统还是2013年入职培训期间去参观的北京南郊观象台。
很遗憾这么多年来才再一次有机会去北京市内的兄弟单位，可见我平时的工作确实与系统内其他单位联系不大。&lt;/p&gt;
&lt;p&gt;上次参观北京观象台，就感觉五环路和对面的高楼可能会对气象观测有一定的影响。
这次参观海淀公园内的海淀国家气象观测站，就更进一步体会到观测台站布设与城市发展之间的冲突。
我们为了取得空间分布更密集的观测资料，就必须尽可能多布设气象站。
但气象站本身需要满足一定的条件才能满足观测基本要求，这就导致气象站的占地及对周围建筑的限制与城市建设之间的矛盾。
南郊观象台位于五环边上，可以通过五环路来维持与周围建筑物的距离。
但海淀观测站就没有这么好的位置条件。虽然观测站位于公园内，却没有足够的空间布设常规观测站，只能采用高山观测站的标准。
观测站正南方向有一颗树，对日照时间的观测会有一定程度的遮挡，所以观测场中的日照观测仪也与标准位置不一样。
目前数值模式预报越来越依赖卫星观测资料，我想也许与这方面的因素有点儿关系。
即便在有能力布设观测站的地方，我们也可能会面临资料系统性偏差的问题，所以资料同化技术才会变得对数值预报模式系统如此重要。
估计北京市区内也没有条件再建新的气象观测站了，也许未来会有各种各样的社会化观测应用到预报预测业务中。&lt;/p&gt;
&lt;p&gt;海淀区气象局不只从事气象观测业务，自2013年改革后，该气象局的主要职责已扩展为综合性气象服务工作。
海淀区气象局局长的报告中提到“海淀区是全球从事气象工作人员密度最大、机构最多区域”，“区内专家多、大咖多、行家里手多，期望高、要求高，挑毛病的多”。
在这样的环境下工作会比较有压力，我对这点深有感触。
我所从事的数值预报业务系统相关工作虽然与外单位专家的直接交流不多，但因为单位同事经常与国际先进中心交流，同时每年都有同事在美国和欧洲等地做访问学者，各位专家对于我们单位在科研和业务上的支撑能力与国际先进水平的差距有很清晰的认识，因此也对我所在的科室有不少的期望，带来不少的工作压力。
我觉得在对于如何处理这种压力这一点上，海淀气象局的做法很值得我们科室学习。&lt;/p&gt;
&lt;p&gt;海淀气象局有中央和地方编制人员共13人，外聘人员12人，两者人数基本相当。
在编制人员数量无法扩大的情况下，海淀区气象局聘用外部人员来加强单位的业务服务能力。
虽然不知道在外聘方面具体是如何操作的，但我觉得无论是海淀区政府还是海淀区气象局都很有魄力。
参加工作以来，我每年都更加深入地体会到，想要做好工作，缺少人手是不行的。
我们科今年来了一名年轻的新同事，五年来终于有新生力量加入。
但很显然，鉴于我们的数值预报模式水平与国际上的差距很明显，单位人力资源投入的重心还是模式的发展研究。
我们今年也开始考虑是否需要引入外部公司，参与数值预报业务系统的运行维护工作，但缺乏明确的政策导向和业务维持经费支持。
仅仅通过工程项目等方式曲线投入，在现在对工程项目监管越来越严格的大趋势下，会带来很大的风险和不确定性。
所以，我觉得我们科室应该向海淀区气象局学习如何引入外聘人员，更好地提供数值预报产品服务。&lt;/p&gt;
&lt;p&gt;海淀区气象局另一个值得我们学习的地方就是通过与辖区内的科研院所和商业公司合作，开发了面向不同服务需求的业务系统，向不同的用户提供针对性服务。
一进门就看到下沉显示屏上实时在立体地球上展示网格预报产品，并且在头顶的显示屏上显示温度和降水随时间变化的曲线。
该套系统源自国家气象信息中心的MOAP平台，在气象中心的会商室也有类似的展示，但海淀区气象局的屏幕更大，效果更震撼。
海淀区气象局还和公司合作开发了&lt;a href="https://www.hdclz.cn:8080/MAP.html"&gt;海淀区菜篮子气象服务保障项目&lt;/a&gt;（需要登录才能查看），为鲜菜运输人员提供沿途的精细化预报服务。
海淀区气象局还和气象公司合作，利用城市三维建筑模型和机器学习算法，构建大风风险警报系统，模拟高层建筑之间的风速，标志大风危险区域。
上面所有的系统都基于Web可视化技术在地图中（三维地球或高德地图）实时动态展示。
数值预报中心目前还是将预先绘制好的图片作为在线展示手段。
运行科的同事很早就在推广实时显示的技术，可惜可能与运行科的职责有关，一直没受到重视。
直到现在，类似的技术已广泛应用在气象领域的各个业务单位。
在技术更新换代如此快速的今天，原地踏步就意味着有可能会被淘汰。
好在，今年有几个工程项目正在尝试应用实时显示技术。
不过这就涉及到了我们需要向海淀气象局学习的另一个方面。&lt;/p&gt;
&lt;p&gt;除了菜篮子工程需要对外服务而单独部署外，海淀气象局展示的内网预报服务系统都集成到同一个平台中，类似国家气象中心所有的预报工具都基于MICAPS平台实现。
集成的平台有助于共享组件，减少重复开发。
这点正是我们科室在执行工程项目时所缺乏的。
我对科室的大部分工程项目在做什么系统都不是很清楚，也从侧面说明我们缺乏统一的平台。
各自为战的结果就是大量的重复工作，开发出来的系统仅在小范围使用，很多功能都没实际应用上。
尽管已经有些努力，但鉴于我们对科研的高度重视，对工程项目的规划和执行不免会沾上科研项目的影子，想要对不同工程项目做一个全面的规划就会变得尤为困难。
再加上我们缺乏管理工程项目的经验，最终的结果也就不难设想了。&lt;/p&gt;
&lt;p&gt;虽然我吐槽了一整篇文章，但我还是对未来充满信心。
这次培训参观了很多单位，学到了很多的经验。
既然兄弟单位可以做的这么好，我们也没有理由怀疑自己的能力。
离完成2020年目标的时间还剩下一年，努力工作的时间足够了。&lt;/p&gt;</description></item><item><title>改造CIMISS MUSIC接口的Python SDK</title><link>https://blog.perillaroc.wang/post/2019/2019-10-25-cimiss-python-api/</link><pubDate>Fri, 25 Oct 2019 18:34:54 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-25-cimiss-python-api/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文仅代表笔者对 2019 年 10 月时 MUSIC 接口发布版本的观点，随着版本更新及对接口进一步研究，笔者后续观点已有变化。&lt;/p&gt;
&lt;p&gt;注：CMADaaS 已提供官方 Python 3 的 MUSIC 接口。&lt;/p&gt;
&lt;p&gt;2021.04.15&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;CIMISS 是全国综合气象信息共享平台 (China Integrated Meteorological Information Service System) 的简称。
由国家气象信息中心牵头建设，用于共享气象业务的数据信息。
对于数值预报中心来说，CIMISS 一般用于检索观测资料。&lt;/p&gt;
&lt;p&gt;MUSIC 接口是气象数据统一服务接口 (MUSIC:Meteorological Unified Service Interface Community) 的简称，是为访问 CIMISS 库中保存的数据而开发的接口。
该接口提供统一、标准、丰富的数据访问服务和应用编程接口 (API)，为应用系统提供唯一权威的数据接入服务。&lt;/p&gt;
&lt;p&gt;今年 6 月 30 日开放测试的 &lt;a href="http://idata.cma/cmadaas/"&gt;气象大数据云平台&lt;/a&gt; 看起来像是对 CIMISS 系统的升级，不仅包含数据，提供包括内置算法在内的计算功能。
该平台提供了 MUSIC 2.0 版的接口。&lt;/p&gt;
&lt;h2 id="music接口的版本"&gt;MUSIC接口的版本&lt;/h2&gt;
&lt;p&gt;当前业务系统正在使用的 MUSIC 接口版本是1.6，从 &lt;a href="http://10.20.76.31:8008/cimissapiweb/"&gt;MUSIC接口内网网址&lt;/a&gt; 下载。&lt;/p&gt;
&lt;p&gt;2.0 版本与 1.6 版本最大的区别在于使用不同的库实现数据序列化。
1.6 版本使用 &lt;a href="https://zeroc.com/products/ice"&gt;ICE&lt;/a&gt;，2.0 版本使用 &lt;a href="https://developers.google.com/protocol-buffers"&gt;Protobuf&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;MUSIC 1.6 版本只提供了 Python 2.6 的 SDK，而没有提供更广泛使用的 Python 2.7 版本。所以我没有使用过这个版本的 SDK。&lt;/p&gt;</description></item><item><title>ecflow学习笔记：节点状态监控工具</title><link>https://blog.perillaroc.wang/post/2019/2019-10-20-ecflow-notebook-ecflow-watchman/</link><pubDate>Sun, 20 Oct 2019 12:17:15 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-20-ecflow-notebook-ecflow-watchman/</guid><description>&lt;blockquote&gt;
&lt;p&gt;警告：本文介绍的工具有严重的&lt;strong&gt;内存泄漏&lt;/strong&gt;问题，请浏览《&lt;a href="https://blog.perillaroc.wang/post/2020/01/2020-01-01-ecflow-notebook-ecflow-watchman-v2/"&gt;ecflow学习笔记：节点状态监控工具V2&lt;/a&gt;》，使用 c++ 版的 ecflow-watchman。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前面的文章介绍了如何构建ecflow的GO语言客户端。本文介绍使用使用该客户端开发节点状态监控工具。&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;在NWPC业务系统监控项目（NWPC Monitor Platform，NMP）中，使用celery定时收集业务系统运行状态。&lt;/p&gt;
&lt;p&gt;采集程序是使用Python API构建的ecflow客户端（&lt;a href="https://github.com/nwpc-oper/nwpc-ecflow-collector"&gt;nwpc-oper/nwpc-ecflow-collector&lt;/a&gt;），部署在HPC的登录节点，NMP通过grpc远程调用采集程序。&lt;/p&gt;
&lt;p&gt;虽然今年上半年更新的本地采集方式有效地解决ecflow API的延时问题，但还有一些问题。&lt;/p&gt;
&lt;p&gt;监控ecflow服务最基本的操作就是获取所有节点的运行状态，但过多使用API查询ecflow服务状态会对整个服务带来繁重的负载，极端情况下会影响整个服务的稳定运行。
所以，如果后续需要进一步增加监控工具，就需要改变现有的数据获取方式，仅用运行一个采集程序，服务所有的后端程序。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/perillaroc/ecflow-watchman"&gt;perillaroc/ecflow-watchman&lt;/a&gt;是为实现上述想法而开发的ecflow节点状态监控工具。&lt;/p&gt;
&lt;p&gt;该工具在一个进程中定时获取需要的ecflow服务状态，并将状态保存到redis中。
后续程序只需定时从redis中读取ecflow的状态，无需调用ecflow API重新获取节点状态。&lt;/p&gt;
&lt;h2 id="架构"&gt;架构&lt;/h2&gt;
&lt;p&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="361px" viewBox="-0.5 -0.5 361 281" content="&amp;lt;mxfile host=&amp;quot;www.draw.io&amp;quot; modified=&amp;quot;2019-10-20T10:54:22.257Z&amp;quot; agent=&amp;quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36&amp;quot; etag=&amp;quot;oSCiqNuGe0SIext60V9e&amp;quot; version=&amp;quot;12.1.3&amp;quot; type=&amp;quot;device&amp;quot; pages=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;diagram id=&amp;quot;BHpz9q006rft7UWH19No&amp;quot; name=&amp;quot;Page-1&amp;quot;&amp;gt;7VhLc5swEP41PqZjHhb42Dhpe2hnOpNDm1NHhgXUCOQR8oP++q5AvPxInBoPyUwvNvtpBdK33+4KJs4i3X2WdJV8EyHwiT0NdxPnbmLbnmXhrwaKCnB8uwJiycIKslrggf0BA04NumYh5D1HJQRXbNUHA5FlEKgeRqUU275bJHj/qSsawwHwEFB+iP5goUoq1Le9Fv8CLE7qJ1tkXo2ktHY2O8kTGoptB3LuJ85CCqGqq3S3AK65q3mp5n06MdosTEKmzpnA3TwiN2y+nIbuMtncub8WcFPTvKF8bXYcCynWimVQ0iXxV5TXEEQc148bAbkBaTalipopnJWFoB82nTi324QpeFjRQI9uURqIJSrlaFl4GdI8KX21gXdTDCn/yFmcIaaE9jYLwzHYndyy1RCJAgSRgpIFupgJ7tRsz4jPqmOxbUNp1z5JJ4y2b0Bq5BM3924ZxgtD8isI9w94gxAFZ0whVSJikVF+36K3fWZbn69CE1VS+BuUKkz20LUSfbaRLln81PM/zGrz0dyuNO52PaswVrVWvcDnA4D7EWsZwHNCM7lLZQzqGT/veEAlcKrYpr+OwYNjHSQDFzSsqkvE4sskHzHOF4JjRum5TkjBjwLEcyXFE3RGSODDMhomAzAFXsyAButmgHutBLDIGBkwoJLdM5VsuWNK2T2QciCBKl3IFUsvLd97Wo4iIMFRLYceLms6UDXf17I3tpbJAckM60TGSpq51uaQLIMVzsA7xvKceA4l16kYDhmb5fkoLXPHVKdjovXYGWn7pTbqdvkG2qx3ZnEio7bZcSLaRKcXmzZUJ6JTK8Hq6KBVxXEljBDRS7tNOfWjlLToOKwEy1TeufN3DbTFwvH7xcIme+8gL/hb8+memqoVtNpqtvLvcvNOt8LmXQf3SDjSe7vEzkhifVW9+wANEv0ABek7bJn7xbyxxzv+ef+r+fkvTWefNWej1vMjh00ugqfyrKn/3t0haP+o+QbyZpwPBxflzev67JB5Mzs3b0Z9R6uX2c0bwbn+jKkDTdU6H7jnRPaJnkOWZHal3HGs6+UOmu0H1Oq80H6Fdu7/Ag==&amp;lt;/diagram&amp;gt;&amp;lt;/mxfile&amp;gt;" onclick="(function(svg){var src=window.event.target||window.event.srcElement;while (src!=null&amp;amp;&amp;amp;src.nodeName.toLowerCase()!='a'){src=src.parentNode;}if(src==null){if(svg.wnd!=null&amp;amp;&amp;amp;!svg.wnd.closed){svg.wnd.focus();}else{var r=function(evt){if(evt.data=='ready'&amp;amp;&amp;amp;evt.source==svg.wnd){svg.wnd.postMessage(decodeURIComponent(svg.getAttribute('content')),'*');window.removeEventListener('message',r);}};window.addEventListener('message',r);svg.wnd=window.open('https://www.draw.io/?client=1&amp;amp;lightbox=1&amp;amp;edit=_blank');}}})(this);" style="cursor:pointer;max-width:100%;max-height:281px;"&gt;&lt;defs/&gt;&lt;g&gt;&lt;rect x="160" y="0" width="200" height="280" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="none"/&gt;&lt;g transform="translate(176.5,7.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="165" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 166px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;goroutine for one ecflow server&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="83" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;goroutine for one ecflow server&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 40 L 60 113.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 60 118.88 L 56.5 111.88 L 60 113.63 L 63.5 111.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;rect x="0" y="0" width="120" height="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/&gt;&lt;g transform="translate(30.5,13.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="58" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 59px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;load config&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="29" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;load config&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 260 90 L 260 110 L 260 100 L 260 113.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 260 118.88 L 256.5 111.88 L 260 113.63 L 263.5 111.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;rect x="200" y="50" width="120" height="40" fill="#ffe6cc" stroke="#d79b00" pointer-events="none"/&gt;&lt;g transform="translate(227.5,63.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="63" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 64px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;create timer&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="32" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;create timer&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="240" width="120" height="40" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/&gt;&lt;g transform="translate(28.5,253.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="61" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 62px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;infinite loop&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="31" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;infinite loop&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 60 160 L 60 233.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 60 238.88 L 56.5 231.88 L 60 233.63 L 63.5 231.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 120 140 L 140 140 L 140 70 L 193.63 70" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 198.88 70 L 191.88 73.5 L 193.63 70 L 191.88 66.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;rect x="0" y="120" width="120" height="40" fill="#ffe6cc" stroke="#d79b00" pointer-events="none"/&gt;&lt;g transform="translate(12.5,126.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="93" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 94px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;create goroutines&lt;br /&gt;for each item&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="47" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;create goroutines&amp;lt;br&amp;gt;for each item&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 260 160 L 260 183.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 260 188.88 L 256.5 181.88 L 260 183.63 L 263.5 181.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;rect x="200" y="120" width="120" height="40" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/&gt;&lt;g transform="translate(234.5,133.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="49" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 50px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;clock tick&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="25" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;clock tick&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 260 230 L 260 250 L 180 250 L 180 140 L 193.63 140" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 198.88 140 L 191.88 143.5 L 193.63 140 L 191.88 136.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;rect x="200" y="190" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(224.5,203.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="none" width="69" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 70px; white-space: nowrap; overflow-wrap: normal; text-align: center;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;collect status&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="35" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica"&gt;collect status&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记：使用SWIG创建golang客户端</title><link>https://blog.perillaroc.wang/post/2019/2019-10-19-ecflow-notebook-a-golang-client-using-swig/</link><pubDate>Sat, 19 Oct 2019 15:18:18 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-19-ecflow-notebook-a-golang-client-using-swig/</guid><description>&lt;blockquote&gt;
&lt;p&gt;警告：依照本文方法实现的ecflow客户端有严重的&lt;strong&gt;内存泄漏&lt;/strong&gt;问题，请不要在长时间运行的程序中使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;之前一篇博文中介绍如何使用ecFlow的C++ API创建客户端（《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-05-26-ecflow-notebook-using-cpp-api/"&gt;ecFlow学习笔记04：使用C++ API&lt;/a&gt;》）。
本文介绍如何基于C++的客户端构建golang客户端。&lt;/p&gt;
&lt;h2 id="golang调用c代码"&gt;golang调用c代码&lt;/h2&gt;
&lt;p&gt;golang提供CGO工具调用C代码，相关信息请参考官方文档《&lt;a href="https://golang.org/cmd/cgo/"&gt;cgo&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;虽然cgo可以使用C++编译器编译C++代码，但必须使用C语言对C++代码进行包装才能在go代码中调用。所以对于使用c++接口的ecflow客户端来说，直接使用cgo非常繁琐。&lt;/p&gt;
&lt;p&gt;好在，有其他工具可以帮助我们在golang中调用c++代码。&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.swig.org/"&gt;SWIG&lt;/a&gt;就属于这样的工具。SWIG是一款实现跨语言调用C/C++代码的工具。&lt;/p&gt;
&lt;p&gt;下面介绍如何使用SWIG创建ecFlow的golang客户端。&lt;/p&gt;
&lt;h2 id="简化的ecflow-c-客户端"&gt;简化的ecFlow c++ 客户端&lt;/h2&gt;
&lt;p&gt;ecflow-cpp-client实现了获取节点状态组成状态树的功能，在golang客户端中，只保留获取节点状态的部分，大幅减少需要的c++代码。&lt;/p&gt;
&lt;p&gt;简化后的c++代码头文件如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#pragma once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; EcflowUtil {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 状态条目，包括节点路径和节点状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NodeStatusRecord&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string path_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string status_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EcflowClientWrapperPrivate&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EcflowClientWrapper&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EcflowClientWrapper() &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;delete&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 使用ip地址和端口号创建client
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EcflowClientWrapper(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;host, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;port);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;~&lt;/span&gt;EcflowClientWrapper();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置连接ecFlow服务器的超时时间，以秒为单位
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setConnectTimeout&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; time_out);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 从ecFlow服务器同步系统状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sync&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 返回状态条目列表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NodeStatusRecord&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; statusRecords() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; status_records_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string errorMessage();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string host_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string port_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; EcflowClientWrapperPrivate&lt;span style="color:#f92672"&gt;*&lt;/span&gt; p_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NodeStatusRecord&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; status_records_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#75715e"&gt;// namespace EcflowUtil
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用ip地址和端口号创建&lt;code&gt;EcflowClientWrapper&lt;/code&gt;，调用&lt;code&gt;sync&lt;/code&gt;方法获取系统状态，最后调用&lt;code&gt;statusRecords&lt;/code&gt;方法获取状态记录列表。&lt;/p&gt;</description></item><item><title>参观中国气象局大院有感</title><link>https://blog.perillaroc.wang/post/2019/2019-10-16-visiting-china-meteorological-administration/</link><pubDate>Wed, 16 Oct 2019 20:08:12 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-16-visiting-china-meteorological-administration/</guid><description>&lt;p&gt;今天下午，大气科学基础知识培训班组织学员参观中国气象局大院各单位，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;华风影视&lt;/li&gt;
&lt;li&gt;公共气象服务中心&lt;/li&gt;
&lt;li&gt;国家气象中心&lt;/li&gt;
&lt;li&gt;国家气象信息中心&lt;/li&gt;
&lt;li&gt;国家卫星气象中心&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我有幸时隔六年后再一次参观大院内的直属单位。&lt;/p&gt;
&lt;p&gt;上一次参观还是在2013年的入职培训。因为时间太远，无法回忆完整的参观流程。
记得我们当时参观了气象中心、气象信息中心、卫星气象中心和华风影视。
各单位参观的部门基本与本次一致，但当时没有参观公共气象服务中心。&lt;/p&gt;
&lt;p&gt;六年的发展时间足够让一个单位展示一个全新的面貌，这正是我这次参观最直接的感受。&lt;/p&gt;
&lt;h2 id="华风影视"&gt;华风影视&lt;/h2&gt;
&lt;p&gt;我对华风影视了解很少，可能与我们单位和华风影视没有直接的业务有关。
本次参观的天气预报直播间感觉比之前更加宽敞，墙上介绍的气象频道主播也大幅度增加。
我个人感觉电视广播和天气预报不算一个行业，所以参观也就只能单纯地看一下而已。&lt;/p&gt;
&lt;h2 id="公共气象服务中心"&gt;公共气象服务中心&lt;/h2&gt;
&lt;p&gt;随后，我们参观了国家预警信息发布中心，属于中国气象局公共服务气象中心。
两者关系类似于国家气象中心和中央气象台，属于一个单位两块牌子。&lt;/p&gt;
&lt;p&gt;其实，我是在今年才注意到大院里有国家预警信息发布中心这个单位。
经过几天前的公共气象服务课，和今天下午的讲解，我才知道到这个单位对于中国气象局，乃至整个国家突发事件应急响应机制都有重要的意义。
通过统一的平台发布各类预警信息，与目前气象局推行的集约化理念不谋而合。
当然讲解老师也提到，平台的推动是一个发展的过程，随着时间推移，大家会看到平台的效能，就会在平台中发送越来越多的信息。其实集约化理念也是一样，只有经过时间的检验，才能真正看到效果如何。&lt;/p&gt;
&lt;p&gt;国家预警信息发布中心的网站是&lt;a href="http://www.12379.cn"&gt;国家突发事件预警信息发布网&lt;/a&gt;，首页是标注各种预警信息的全球地图，非常直观方便。这才是提供服务的网站该有的样子。
很多时候，用户往往只对自己需要的信息感兴趣。我现在大多数情况下都使用手机自带的天气预报APP查看天气预报。
当打开天气预报APP时，我只需要查看当天或者最近几天的天气情况，而不需要诸如娱乐、养生、视频、情感、美食等其它内容。墨迹天气在这点上就特别“墨迹”，我总觉得它在提供服务这方面有点儿跑偏，远不如国家突发事件预警信息发布网的专注。当然也许是盈利压力导致墨迹天气APP内容的持续增加，但想做平台的APP都突破不了微信的天花板，所以还不如专注于提高自己的核心竞争力。&lt;/p&gt;
&lt;p&gt;之前的公共气象服务课介绍过，气象服务是一个快速发展的领域。我感觉我们局大院对如何提供气象服务还没有清晰的共识。
今年8月份预报与网络司的《气象数据管理规定（征求意见稿）》中将气象局的直属单位划分为气象信息业务单位、气象数据服务单位和其他业务科研单位三种类型。规定由气象信息业务单位向非盈利部门提供数据，由气象数据服务单位向经营性部门提供气象数据，其他业务科研单位负责生产、提交数据并协助服务单位开展服务。
该规定目前还没有正式发布，应该还在修改阶段。&lt;/p&gt;
&lt;p&gt;气象服务说到底就是气象数据的服务，该规定将打破现有大院内的气象服务格局。
但我个人不太看好将数据的生产和服务交给不同部门的这种分工方式。从目前中国气象局高性能计算机上各个单位跑的众多数值天气预报模式业务系统就可以看到，不管单位如何分类，大家还是需要自己生产数据。所以职责各自分开后的效果如何，可能得等规定出台的几年后再评估了。&lt;/p&gt;
&lt;h2 id="国家气象中心"&gt;国家气象中心&lt;/h2&gt;
&lt;p&gt;公共服务中心之后，我们参观了国家气象中心的重新装修后今年刚投入使用的会商室。
我也是第一次来重新设计后的会商室，果然与之前的面貌完全不同。&lt;/p&gt;
&lt;p&gt;最明显的改变在于新的布局充分利用会商室南侧整个墙面的玻璃窗，增加空间的自然采光，让会商室变得非常明亮。
而不像之前的会商室那样，将窗户挡在电脑屏幕墙外侧，有一种压抑感。
另一个显著的变化就是采用吊顶形式的标牌，指示各个区域属于哪些岗位，并列出“航空气象”和“水文气象”等专业气象服务岗位。之前我没注意过气象中心会将航空和水文放在和强天气、台海相同的位置上，联想到气象中心近几年组建了环境气象中心，可能气象中心会越来越重视专业气象服务领域。
还有一个变化是新的会商室采用了各种先进的信息化技术。比如会商室正中吊起的4块显示屏，实时展示预报结果和其他业务信息。旁边的触摸屏展示了模式和网格预报的动态可视化产品。整个会商室采用云桌面的形式，不再设置物理主机，增加办公空间，让会商室显得更加宽敞。参观的时候正好有七八名的同事在某个岗位前谈论，完全不显得拥挤。&lt;/p&gt;
&lt;p&gt;人性化的设计和信息技术的应用能有效地提高工作效率，会商室的设计具有很好的示范意义。
今天参观的其他业务平台，不是采用与之前的会商室一样的风格，就是太偏重于展示，缺乏让我耳目一新的感觉。
我也理解了为什么李泽椿院士在不忘初心报告中会提议可以考虑下将国家气象中心青年之星称号颁发给主持新会商室设计的同事。&lt;/p&gt;
&lt;h2 id="国家气象信息中心"&gt;国家气象信息中心&lt;/h2&gt;
&lt;p&gt;离开会商室后，我们参观了位于新建办公楼二楼的国家气象信息中心天镜平台。
新的气候楼使用更加现代的办公楼布局，天镜平台位于堪比演播室的宽敞大厅中，巨幅的屏幕提供各种不同类型的监控信息。
天镜大厅旁边就是中国气象局最新一代高性能计算机派-曙光的机房。&lt;/p&gt;
&lt;p&gt;虽然我每天都会与派-曙光打交道，但我还是第一次看到它的真容。在气象局部署上一代高性能计算机IBM-HPC时，需要对老信息中心楼的二层重新加固并在楼外安装大量的设备用于散热。新的办公楼就完全满足高性能计算机机房的各项要求，新的机房看起来还有不少的扩展空间。&lt;/p&gt;
&lt;p&gt;讲解老师介绍目前派-曙光在全球气象领域排名第四位，仅落后于日本、欧洲、美国。
虽然HPC的性能高低不代表数值预报模式的性能高低，但也能从另一个侧面反映为数值预报模式业务研发提供的计算能力。
派-曙光比上一代HPC提供更强大的计算能力，从2018年投入业务应用后，我们的数值预报业务模式有了大幅度的升级，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同化系统升级到全球四维变分同化&lt;/li&gt;
&lt;li&gt;具有31个成员的GRAPES全球集合预报投入业务运行&lt;/li&gt;
&lt;li&gt;区域3km分辨率系统从中国东部区域扩展到中国范围&lt;/li&gt;
&lt;li&gt;区域台风模式升级到亚太区域9km分辨率，并提高垂直层次&lt;/li&gt;
&lt;li&gt;区域GRAPES集合预报提高分辨率等等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数值预报模式的发展依赖于计算能力的提升，但可以看到，目前派-曙光已出现大量的作业排队现象，高性能计算资源严重不足。
对于气象局五年的HPC升级周期来说，计算资源增长太快了。ECMWF将于2020年在意大利建成新的数据中心，提供新的高性能计算机，届时我们气象局的HPC计算能力将与ECMWF进一步拉开距离。不过，也许在数值预报模式的HPC计算能力上，我们与ECMWF永远会有一定的差距。因为我们的HPC属于整个中国气象局，尽管数值预报中心是最大的用户，上面还同时运行大量的其他模式系统。
就像数值预报中心曾经同时运行引进的T639模式和自主开发的GRAPES模式一样，HPC上运行着各种各样的数值预报模式。&lt;/p&gt;
&lt;p&gt;数值预报中心经过最近几年的努力，已经从双核模式逐渐过渡到单核模式，而且对于天气预报模式也不会再走引进路线。
不过，“引进技术，还是自主研发”是个仁者见仁智者见智的问题，从不同角度出发，往往会得到完全相反的结果。
无论如何，单就HPC计算能力这一点，我们与世界先进气象中心相比还有很大的差距。&lt;/p&gt;
&lt;h2 id="国家卫星气象中心"&gt;国家卫星气象中心&lt;/h2&gt;
&lt;p&gt;最后，我们参观了国家卫星气象中心。卫星中心引进了智能机器人作为讲解员，不愧为走在时代最前沿的单位。
风云4号静止轨道卫星的发射成功代表我国的气象卫星事业已走在国际的前列。
当前的数值模式已离不开卫星的观测资料，我们单位也在第一时间将风云4号卫星的观测接入到模式中，并与卫星中心保持密切的合作关系。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;经过半天的参观，我有很多收获。如果还像以前那样局限于自己单位的小圈子，就容易安于现状，而忽视整个行业的发展趋势。
正如单位领导说的，我在单位信息化方面缺乏突破性的工作，数值预报中心的业务系统和服务模式依然与六年前没有本质上的区别。
在后续工作中，我会学习各个单位和部门的先进经验，努力在单位的信息化建设方面做出自己的贡献。&lt;/p&gt;</description></item><item><title>NWPC高性能计算机环境介绍</title><link>https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/</link><pubDate>Mon, 07 Oct 2019 17:18:25 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/</guid><description>&lt;p&gt;本系列文章源于为数值预报中心 2019 年 GRAPES 培训准备的 PPT，包括如下章节：&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;汇总&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-09-03-nwpc-hpc-tutorial-hpc-introduction/"&gt;高性能计算机概况&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-09-15-nwpc-hpc-tutorial-login/"&gt;系统登录&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-filesystem/"&gt;文件系统&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-software/"&gt;应用软件&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-06-nwpc-hpc-tutorial-batch-system/"&gt;作业管理&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-data-management/"&gt;数据管理&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>NWPC高性能计算机环境介绍：数据管理</title><link>https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-data-management/</link><pubDate>Mon, 07 Oct 2019 17:03:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-data-management/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;NWPC高性能计算机环境介绍&lt;/a&gt; 系列文章的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="业务系统数据存储"&gt;业务系统数据存储&lt;/h2&gt;
&lt;p&gt;业务系统数据存储分为不同的级别，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/storage-level.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;业务系统数据存储级别&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;数值预报业务系统在 HPC 上运行，因此数据会保存在 HPC 上，包括运行目录、临时归档目录和归档目录。&lt;/p&gt;
&lt;p&gt;但因为数值预报数据量太大，HPC 上无法保存长时间序列的数据，因此数据也会保存到二级存储中。&lt;/p&gt;
&lt;p&gt;对于需要使用实时数据的用户来说，建议使用 HPC 上的归档数据 (archive)，能保证数据路径一直有效。&lt;/p&gt;
&lt;h2 id="归档目录结构"&gt;归档目录结构&lt;/h2&gt;
&lt;p&gt;每个业务系统的归档目录结构都相似，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/archive-dir.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;归档目录结构，不同系统的目录仅有细微差别&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="数据种类"&gt;数据种类&lt;/h2&gt;
&lt;p&gt;常见的数据种类如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Obs：观测数据&lt;/li&gt;
&lt;li&gt;An：同化&lt;/li&gt;
&lt;li&gt;Fcst：模式积分输出&lt;/li&gt;
&lt;li&gt;Prod-graph：图形产品&lt;/li&gt;
&lt;li&gt;Prod-grib：GRIB数据产品&lt;/li&gt;
&lt;li&gt;Vrfy：检验产品&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二级存储"&gt;二级存储&lt;/h2&gt;
&lt;p&gt;因为各种各样不可描述的原因，目前我们仅能使用HPC访问二级存储。&lt;/p&gt;
&lt;p&gt;使用特定的账户登陆 &lt;code&gt;dt.piop.nmic.cn&lt;/code&gt;，访问如下已挂载的目录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/sstorage1&lt;/li&gt;
&lt;li&gt;/sstorage2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/sstorage-space.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;二级存储已挂载到HPC上的存储空间&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;我们正在努力推动二级存储对所有 HPC 账户开放。
后续也许会有更方便的访问方式。&lt;/p&gt;
&lt;h2 id="查找业务系统数据文件路径工具"&gt;查找业务系统数据文件路径工具&lt;/h2&gt;
&lt;p&gt;NWPC 开发的 &lt;code&gt;nwpc_data_client&lt;/code&gt; 工具可以用于查找业务系统数据文件路径。&lt;/p&gt;
&lt;p&gt;该工具是一个开源项目，感兴趣可以访问项目网址。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/nwpc-oper/nwpc-data-client"&gt;https://github.com/nwpc-oper/nwpc-data-client&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;使用下面的命令查找 2019 年 8 月 28 日 00 时次 0 时效的 GRAPES GFS 模式原始分辨率 GRIB2 数据文件路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/g1/u/nwp_pd/nwpc_data_client/bin/nwpc_data_client &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	local &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --config-dir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/g1/u/nwp_pd/nwpc_data_client/config/local &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --data-type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;grapes_gfs_gmf/grib2/orig &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2019082800&lt;/span&gt; 0h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;命令返回如下的文件路径&lt;/p&gt;</description></item><item><title>NWPC高性能计算机环境介绍：作业管理</title><link>https://blog.perillaroc.wang/post/2019/2019-10-06-nwpc-hpc-tutorial-batch-system/</link><pubDate>Sun, 06 Oct 2019 21:30:14 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-06-nwpc-hpc-tutorial-batch-system/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;NWPC高性能计算机环境介绍&lt;/a&gt; 系列文章的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文内容部分参考 ECMWF 的文档《&lt;a href="https://confluence.ecmwf.int/display/UDOC/Batch+Systems"&gt;Batch Systems&lt;/a&gt;》。&lt;/p&gt;
&lt;h2 id="直接运行与批处理"&gt;直接运行与批处理&lt;/h2&gt;
&lt;p&gt;之前章节介绍过，高性能计算机系统由少量的登陆节点和大量的计算节点组成。&lt;/p&gt;
&lt;p&gt;直接在登录节点上运行程序就是下图所示的情形，登陆节点上跑了大量的程序，导致登陆节点响应速度降低，而大量计算节点处于空闲状态。&lt;/p&gt;
&lt;p&gt;我们在平时工作中经常会遇到登陆节点执行命令卡住的情况，一个可能的原因就是因为某用户在登录节点上运行大量程序，导致 CPU 占用过高。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/interactive-work.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;登陆节点上直接运行程序，图片来自 ECMWF 的《Batch Systems》&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;我们应该将作业提交到计算节点上以批处理的方式运行，如下图所示。这就需要使用作业调度系统。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/batch-work.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;提交到计算节点上运行程序，图片来自 ECMWF 的《Batch Systems》&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为了保证系统正常提供服务，请不要在登录节点上运行程序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="直接运行"&gt;直接运行&lt;/h2&gt;
&lt;p&gt;某些特殊情况下，我们仍然需要在登录节点上运行程序，例如编辑文件、编译程序等。&lt;/p&gt;
&lt;p&gt;登录节点上直接运行程序有下面几种方式：&lt;/p&gt;
&lt;h3 id="交互方式"&gt;交互方式&lt;/h3&gt;
&lt;p&gt;命令行输入程序名及参数，程序在登录终端前台运行，程序运行结束才能运行下一条命令。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./your_program arg1 arg2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="后台方式"&gt;后台方式&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;&amp;amp;&lt;/code&gt; 在后台运行程序，同时执行其他操作。
此种方式需要保证登录终端一直存在才能运行结束。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./your_program arg1 arg2 &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们使用 ecFlow UI 监控数值预报业务系统一般使用这种方式。&lt;/p&gt;
&lt;p&gt;如果需要在登录终端退出后依然运行程序，则使用 &lt;code&gt;nohup&lt;/code&gt; 运行程序。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nohup ./your_program arg1 arg2 &amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ecFlow 的后台服务就是使用 &lt;code&gt;nohup&lt;/code&gt; 命令使程序与终端解绑。&lt;/p&gt;
&lt;h2 id="作业调度系统"&gt;作业调度系统&lt;/h2&gt;
&lt;p&gt;CMA-PI 上的批处理由 Gridview 综合管理系统实现，该系统基于开源作业调度系统 &lt;a href="https://slurm.schedmd.com/"&gt;Slurm Workload Manager&lt;/a&gt; 开发。&lt;/p&gt;
&lt;p&gt;Slurm Workload Manager 主要提供一下功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运行和管理批处理作业&lt;/li&gt;
&lt;li&gt;资源申请&lt;/li&gt;
&lt;li&gt;作业调度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在作业调度系统中运行的批处理作业一般都是 shell 脚本，使用某些&lt;strong&gt;特殊指令&lt;/strong&gt;描述作业属性。&lt;/p&gt;</description></item><item><title>NWPC高性能计算机环境介绍：应用软件</title><link>https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-software/</link><pubDate>Sat, 05 Oct 2019 21:00:54 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-software/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;NWPC高性能计算机环境介绍&lt;/a&gt; 系列文章的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CMA-PI 的软件资源如下所示。
最底层是 redhat 操作系统，上一层是分布式文件管理系统和作业调度系统，再上一层是编译器和调试器，最顶层是应用软件和函数库。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/hpc-software.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PI 软件资源分层图，图片来自 PI-曙光培训 PPT&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="软件使用"&gt;软件使用&lt;/h2&gt;
&lt;p&gt;使用软件需要进行设置，下面首先展示如何手动设置软件环境。&lt;/p&gt;
&lt;h3 id="如何才能运行python程序"&gt;如何才能运行Python程序&lt;/h3&gt;
&lt;p&gt;要使用用户编译的 python 3.7 环境运行 python 程序，需要配置一系列的环境变量：&lt;/p&gt;
&lt;p&gt;定位可执行程序 python：设置环境变量 &lt;code&gt;PATH&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:/g11/wangdp/lang/python/python3/bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定位动态链接库：设置环境变量 &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export LD_LIBRARY_PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;LD_LIBRARY_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:/g11/wangdp/lang/python/python3/lib
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定位 Python 包：设置环境变量&lt;code&gt;PYTHONPATH&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PYTHONPATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;LD_LIBRARY_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:/g11/wangdp/lang/python/python3/lib/python3.7
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="软件管理方式"&gt;软件管理方式&lt;/h3&gt;
&lt;p&gt;在上一代高性能计算机 IBM AIX 上，我们手动执行上面一节列出的代码设置环境变量。
为了方便使用，会将环境配置代码写入 &lt;code&gt;~/.bashrc&lt;/code&gt; 或 &lt;code&gt;~/.profile&lt;/code&gt; 中，在系统登录时自动执行。&lt;/p&gt;
&lt;p&gt;以使用 GrADS 2.0.2 软件包为例，IBM AIX 上需要在配置文件中加入下面的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GRADS20&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/cma/u/app/grads-2.0.2
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GADDIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GRADS20&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GASCRP&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GRADS20&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/lib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GRAPES20&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export LD_LIBRARY_PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;LD_LIBRARY_PATH&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;GASCRP&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 HPC PI 上，我们使用 module 命令管理软件环境。
登录后，使用 module 动态加载，软件包由管理员配置。&lt;/p&gt;</description></item><item><title>NWPC高性能计算机环境介绍：文件系统</title><link>https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-filesystem/</link><pubDate>Sat, 05 Oct 2019 20:44:40 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-filesystem/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;NWPC高性能计算机环境介绍&lt;/a&gt; 系列文章的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="用户文件系统类型"&gt;用户文件系统类型&lt;/h2&gt;
&lt;p&gt;CMA-PI 的用户文件系统包括下面三种&lt;/p&gt;
&lt;h3 id="home"&gt;HOME&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;${HOME}&lt;/code&gt; 是用户主目录，使用 quota 管理，一般空间较小，定期备份。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/g1/u/wangdp&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="workdir"&gt;WORKDIR&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;${WORKDIR}&lt;/code&gt; 是用户数据空间，使用 quota 管理，空间比用户主目录大，不备份。&lt;/p&gt;
&lt;p&gt;不同用户的数据空间可能放到不同的分区下，例如我个人账户的数据空间就在 &lt;code&gt;g11&lt;/code&gt; 分区。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/g11/wangdp&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="jobdir"&gt;JOBDIR&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;${JOBDIR}&lt;/code&gt; 是作业运行临时空间，定期删除 (1个月？，未定)，使用 quota 备份。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/g8/JOB_TMP/wangdp&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="查看空间限额"&gt;查看空间限额&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;quotainfo&lt;/code&gt; 查看磁盘空间限额。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/user-quotainfo.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;quotainfo查看空间限额&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;鉴于备份机制的不确定性以及之前出现过数据丢失的现象，建议：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关键数据建议使用额外工具备份，例如使用 METCODE/GIT 等版本控制工具&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NWPC高性能计算机环境介绍&lt;/strong&gt; 系列文章&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;汇总&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-09-03-nwpc-hpc-tutorial-hpc-introduction/"&gt;高性能计算机概况&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-09-15-nwpc-hpc-tutorial-login/"&gt;系统登录&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-filesystem/"&gt;文件系统&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-05-nwpc-hpc-tutorial-software/"&gt;应用软件&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-06-nwpc-hpc-tutorial-batch-system/"&gt;作业管理&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-data-management/"&gt;数据管理&lt;/a&gt;&lt;/p&gt;</description></item><item><title>NWPC笔记：检查输出数据</title><link>https://blog.perillaroc.wang/post/2019/2019-09-16-nwpc-system-notebook-check-output-data/</link><pubDate>Mon, 16 Sep 2019 21:25:53 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-09-16-nwpc-system-notebook-check-output-data/</guid><description>&lt;p&gt;数值预报模式积分一般会输出多个不同时效的预报结果文件，产品制作模块一般会对每个时效的文件进行处理并制作数据、图片等产品。
为了提高产品时效性，需要在数据文件生成后就立即开始制作产品，也就是在模式积分过程中运行后处理模块。&lt;/p&gt;
&lt;p&gt;数值预报中心的业务系统使用两种方法来实现模式积分与后处理同时进行，下面首先介绍这两种后处理系统的模型。&lt;/p&gt;
&lt;h2 id="后处理系统模型"&gt;后处理系统模型&lt;/h2&gt;
&lt;h3 id="触发器"&gt;触发器&lt;/h3&gt;
&lt;p&gt;SMS和ecFlow提供触发器机制用于解决不同任务之间的依赖关系，结合前一篇文章《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-08-07-nwpc-system-notebook-progress-for-forecast-task/"&gt;NWPC业务系统笔记：获取模式积分任务的执行进度&lt;/a&gt;》中介绍的方法，可以为每个时效的后处理任务建立trigger，随着积分过程制作产品。&lt;/p&gt;
&lt;p&gt;基于触发器的后处理系统模型是数值预报中心一直使用的后处理模型。尽管大部分业务系统将模式系统与产品制作系统分离，仍有部分业务系统使用该种模式，包括集合预报、区域台风、环境模式等。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/ecflow/geps-trigger.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;GRAPES GEPS的024时效efi任务触发器，需要所有模式积分024时效的unidata任务完成后才能触发&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;该模式不需要额外的机制来处理数据依赖关系，可以在数据完成（触发器满足条件）时立即启动后处理任务。&lt;/p&gt;
&lt;p&gt;配置得当的trigger可以完全覆盖所有前置任务（数据）需求，触发器模式的复杂性就在于此。
例如上图中efi_024任务需要使用所有模式积分的数据，所以设定了31个触发条件。
不过我们使用python构建ecFlow的定义文件，通过for循环构建触发器比手动编写要容易实现。&lt;/p&gt;
&lt;p&gt;下面是两种方式的对比。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用for循环&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tk_efi_hhh&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_part_trigger(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;../../control/unipost/unipost_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;hhh&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; == complete&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; pair_index &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; mem_index &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tk_efi_hhh&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_part_trigger(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;../../members/pair_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;pair_index&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/mem&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;mem_index&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/unipost/unipost_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;hhh&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; == complete&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;使用硬编码&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tk_efi_hhh&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_trigger(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;../../control/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_01/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_01/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_02/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_02/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_03/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_03/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_04/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_04/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_05/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_05/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_06/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_06/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_07/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_07/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_08/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_08/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_09/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_09/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_10/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_10/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_11/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_11/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_12/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_12/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_13/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_13/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_14/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_14/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_15/mem01/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34; and ../../members/pair_15/mem02/unipost/unipost_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;hhh&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; == complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="数据检查"&gt;数据检查&lt;/h3&gt;
&lt;p&gt;最近几年，数值预报中心的大部分业务系统已将产品制作模块从模式系统中分离，构建单独的产品制作系统。
最初拆分系统的目的应该是分解系统构建任务。
但后来发现分离后处理系统能有效保障主模式系统流程的简洁，避免任务众多的后处理模块影响整个模式积分的进程，因为任务越多就越容易出错。
同时，产品制作与分发经常需要更新升级，单独建立后处理系统能避免对主模式系统的影响，也有利于系统调试。&lt;/p&gt;</description></item><item><title>NWPC高性能计算机环境介绍：系统登录</title><link>https://blog.perillaroc.wang/post/2019/2019-09-15-nwpc-hpc-tutorial-login/</link><pubDate>Sun, 15 Sep 2019 20:30:22 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-09-15-nwpc-hpc-tutorial-login/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;NWPC高性能计算机环境介绍&lt;/a&gt; 系列文章的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="登录方式"&gt;登录方式&lt;/h2&gt;
&lt;p&gt;HPC 使用 SSH 登录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户名+密码：默认的方式&lt;/li&gt;
&lt;li&gt;用户名+秘钥：需要配置秘钥，可以实现无密码登录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="登录工具"&gt;登录工具&lt;/h2&gt;
&lt;p&gt;登录命令行需要准备 SSH 客户端，如果想使用图形软件，还需要 X11 服务。&lt;/p&gt;
&lt;h3 id="windows"&gt;Windows&lt;/h3&gt;
&lt;p&gt;推荐使用 &lt;a href="https://www.netsarang.com/zh/xmanager/"&gt;XManager&lt;/a&gt; 和 &lt;a href="https://mobaxterm.mobatek.net/"&gt;MobaXterm&lt;/a&gt; 等带有 X11 服务的 SSH 登录软件，但这两个软件都是收费软件，使用前请三思。
也可以单独使用 SSH 命令行，例如 &lt;a href="https://www.chiark.greenend.org.uk/~sgtatham/putty/"&gt;Putty&lt;/a&gt;、&lt;a href="https://www.vandyke.com/products/securecrt/"&gt;SecureCRT&lt;/a&gt;等，Windows 10 自带的 WSL 也提供 ssh 命令。
X11 服务开源软件可以使用 Xming，但我没有用过。&lt;/p&gt;
&lt;h3 id="linux"&gt;Linux&lt;/h3&gt;
&lt;p&gt;Linux 自带的终端就可以实现 SSH 登陆，X Windows System 和 GNOME、KDE 等桌面提供 X11 服务。
当然可以安装第三方命令行终端，例如 Terminator。&lt;/p&gt;
&lt;h3 id="mac"&gt;Mac&lt;/h3&gt;
&lt;p&gt;Mac 与 Linux 类似，自带的终端和第三方终端都可以实现 SSH 登陆。
X11 服务需要使用 &lt;a href="https://www.xquartz.org/"&gt;XQuartz&lt;/a&gt;，就我个人使用经验来看，XQuartz 不太稳定。
我一般使用 Microsoft 远程桌面工具直接连接到工作电脑。&lt;/p&gt;
&lt;h2 id="域名访问"&gt;域名访问&lt;/h2&gt;
&lt;p&gt;CMA-PI 的两个子系统有不同的登陆域名：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pird.nmic.cn&lt;/code&gt;：科研分区，子系统1&lt;/li&gt;
&lt;li&gt;&lt;code&gt;piop.nmic.cn&lt;/code&gt;：业务分区，子系统2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同的科研用户默认分配给不同的子系统。数值预报业务系统的账户都分配在业务分区。&lt;/p&gt;
&lt;p&gt;当用户使用域名登陆时，系统会根据登录节点的负载，自动分配到较空闲的一个。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/login-pird.png" alt=""&gt;
&lt;strong&gt;子系统1，login_a01 ~ login_a10&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>NWPC高性能计算机环境介绍：高性能计算机概况</title><link>https://blog.perillaroc.wang/post/2019/2019-09-03-nwpc-hpc-tutorial-hpc-introduction/</link><pubDate>Tue, 03 Sep 2019 20:37:24 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-09-03-nwpc-hpc-tutorial-hpc-introduction/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;a href="https://blog.perillaroc.wang/post/2019/2019-10-07-nwpc-hpc-tutorial-overall/"&gt;NWPC高性能计算机环境介绍&lt;/a&gt; 系列文章的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="高性能计算机系统"&gt;高性能计算机系统&lt;/h2&gt;
&lt;p&gt;CMA 新一代高性能计算机PI-曙光系统由两套互为备份的子系统构成。有如下的特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通用 Intel CPU 处理器&lt;/li&gt;
&lt;li&gt;Cluster 架构&lt;/li&gt;
&lt;li&gt;计算资源独立&lt;/li&gt;
&lt;li&gt;存储资源共享&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;高性能计算机的架构如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/cma-hpc.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;CMA-PI 架构，图片来自《曙光高性能计算机用户使用简介-201805》&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;从图中可以看到，高性能计算机内部使用高速计算机网络连接，仅前后处理节点 (串行节点) 和管理登陆节点与 CMA 局域网连接，计算节点和并行存储与外界隔离，保障整个 HPC 系统的安全性。&lt;/p&gt;
&lt;p&gt;右下角的试验子系统包含 GPU 和众核节点，不过遗憾的是直到PI-曙光投入应用一年半后的现在，我依然没有访问该子系统的权限，所以本介绍不包括该试验子系统。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2022 补充：试验子系统已对 NWPC 开放，2021 年 NWPC 举办的机器学习培训已使用该子系统&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="子系统配置"&gt;子系统配置&lt;/h2&gt;
&lt;p&gt;两个子系统的配置如下图所示，可以看到两个子系统配置几乎完全一样，除了子系统 2 采用更高级的液冷刀片服务器。
所以数值预报业务系统部署在子系统 2。
两个子系统的存储节点可以被所有节点共享访问，所以位于子系统 1 的用户也可以访问数值预报业务系统生成的数据。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/nwpc-tutorial/cma-pi-hardware.svg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;CMA-PI 两个子系统的配置&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="节点配置"&gt;节点配置&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;硬件配置&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU：2 颗 Intel Xeon Gold 6142 处理器，16 核，主频 2.6GHz&lt;/li&gt;
&lt;li&gt;内存：12 通道 DDR4 2666 内存（一般节点 192GB / 大内存节点 384GB）&lt;/li&gt;
&lt;li&gt;通讯网络：100Gb/s InfiniBand EDR 高速网络&lt;/li&gt;
&lt;li&gt;存储：Parastor 300 并行存储系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;软件配置&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>NWPC笔记：获取模式积分任务的执行进度</title><link>https://blog.perillaroc.wang/post/2019/2019-08-07-nwpc-system-notebook-progress-for-forecast-task/</link><pubDate>Wed, 07 Aug 2019 06:00:24 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-08-07-nwpc-system-notebook-progress-for-forecast-task/</guid><description>&lt;p&gt;数值预报模式积分运行时间较长，我们一般会使用 ecFlow 的 meter 标尺功能展示模式积分的进度，该进度也用于触发后续的后处理任务。
虽然大部分后处理任务已与模式积分系统分离，形成单独的后处理系统，但因为 ecFlow 无法提供跨服务的标尺触发功能，所以目前标尺的作用主要是为运维人员提供直观的积分进度信息。&lt;/p&gt;
&lt;p&gt;下面介绍几种我们曾经使用和目前正在使用的生成 meter 标尺的方式。&lt;/p&gt;
&lt;h2 id="模式程序调用-ecflow_client"&gt;模式程序调用 ecflow_client&lt;/h2&gt;
&lt;p&gt;在模式代码中直接调用 shell 命令，在 ecFlow 的前任 SMS 时代，我们的模式系统采用的都是这种方法。&lt;/p&gt;
&lt;p&gt;GRAPES GFS 2.1.1.1 版中调用 &lt;code&gt;smsmeter&lt;/code&gt; 的语句如下所示。每步积分结束后，会打印一行语句到标准输出，并执行shell命令。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fortran" data-lang="fortran"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;IF&lt;/span&gt; ( on_monitor() ) &lt;span style="color:#66d9ef"&gt;THEN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WRITE&lt;/span&gt; ( message , FMT &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;(&amp;#34;processing for step &amp;#34;,I8)&amp;#39;&lt;/span&gt; ) step
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;CALL&lt;/span&gt; end_timing ( TRIM(message) )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;! add for sms monitor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WRITE&lt;/span&gt;(smscall,&lt;span style="color:#e6db74"&gt;&amp;#39; (&amp;#39;&amp;#39;smsmeter steps &amp;#39;&amp;#39;,I8,&amp;#39;&amp;#39;&amp;amp;&amp;#39;&amp;#39;) &amp;#39;&lt;/span&gt;) step
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;CALL&lt;/span&gt; SYSTEM(TRIM(smscall))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;ENDIF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如下图所示：&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/ecflow/forecast-step-system-call.png"&gt;&lt;figcaption&gt;
			&lt;h4&gt;模式积分过程中执行 smsmeter 系统调用&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;这种方式最直接，不需要设置额外的任务。
但随着模式分辨率的提高，对模式计算效率的要求越来越高，执行 shell 命令额外耗费时间逐渐成为性能瓶颈。
所以目前我们的业务系统已基本不再使用这种方式更新模式积分进度，而使用下面两种间接的监控方式。&lt;/p&gt;
&lt;h2 id="检测输出日志"&gt;检测输出日志&lt;/h2&gt;
&lt;p&gt;上面代码中可以看到，每步积分会向标准输出中打印一行带有积分步数和执行时间的语句。
GRAPES GFS的积分输出的 std.out.0000 文件中有类似的内容：&lt;/p&gt;</description></item><item><title>使用go generate将YAML配置文件内嵌到项目中</title><link>https://blog.perillaroc.wang/post/2019/2019-08-03-generate-go-code-for-yaml/</link><pubDate>Sat, 03 Aug 2019 16:43:29 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-08-03-generate-go-code-for-yaml/</guid><description>&lt;p&gt;很多命令行程序会使用到配置文件，本文首先介绍命令行程序使用配置文件的几种方式，然后介绍如何在 Go 程序中内置 YAML 配置文件。&lt;/p&gt;
&lt;h2 id="使用配置文件的常见方式"&gt;使用配置文件的常见方式&lt;/h2&gt;
&lt;p&gt;命令行程序使用配置文件有如下几种方式：&lt;/p&gt;
&lt;h3 id="固定目录"&gt;固定目录&lt;/h3&gt;
&lt;p&gt;例如使用程序目录中的 config 目录，或者使用诸如 /etc 等系统目录。&lt;/p&gt;
&lt;h3 id="环境变量"&gt;环境变量&lt;/h3&gt;
&lt;p&gt;使用环境变量设置配置文件的目录。例如 ecCodes 使用 &lt;code&gt;ECCOES_DEFINITION_PATH&lt;/code&gt; 设置 definition 目录。&lt;/p&gt;
&lt;h3 id="命令行参数指定"&gt;命令行参数指定&lt;/h3&gt;
&lt;p&gt;更直接的方式就是在命令行参数中指定配置文件路径，这也是最容易实现的一种方式。&lt;/p&gt;
&lt;h2 id="我常使用的方法"&gt;我常使用的方法&lt;/h2&gt;
&lt;p&gt;我个人编写的程序一般都采用命令行或环境变量方式。&lt;/p&gt;
&lt;p&gt;每次执行命令都指定配置文件的路径十分不方便，对用户不友好。所以我一般对命令进行一定的封装，内置配置文件路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ECFLOW_CHECKER_CONFIG_PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/g11/wangdp/project/work/nost-go/ecflow-client-go/dist/conf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/g11/wangdp/project/work/nost-go/ecflow-client-go/bin/ecflow_checker $@
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;HPC 上普通用户没有管理员权限，无法使用固定的系统目录。
这种方式只能将配置目录指向某个用户目录，有一定的风险。
而且业务系统中不允许使用非业务账户下的文件，所以这样的程序只能将配置文件保存到每个业务系统中，使用非常繁琐。&lt;/p&gt;
&lt;h2 id="hugo的方式"&gt;Hugo的方式&lt;/h2&gt;
&lt;p&gt;在使用 Hugo 过程中，发现 Hugo 仅使用一个二进制程序就能自动生成多种代码模板，一定是将模板编译到程序中。&lt;/p&gt;
&lt;p&gt;研究 Hugo 源码发现，Hugo 使用 go generate 根据模板 HTML 文件生成 Go 源码文件 &lt;code&gt;templates.autogen.go&lt;/code&gt;，将模板集成到代码中。&lt;/p&gt;
&lt;p&gt;生成程序参见&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/generate/generate.go"&gt;https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/generate/generate.go&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;核心是将模板保存到下面的数组中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EmbeddedTemplates&lt;/span&gt; = [][&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;template&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;, &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;template&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;数组元素是二维字符串数组，包括模板名称和模板内容。&lt;/p&gt;
&lt;p&gt;文件中使用 &lt;code&gt;go generate&lt;/code&gt; 的注释语法，支持使用 &lt;code&gt;go generate&lt;/code&gt; 直接运行，生成文件。&lt;/p&gt;</description></item><item><title>从项目招标文件看工作流软件的功能要求</title><link>https://blog.perillaroc.wang/post/2019/2019-08-01-what-is-a-workflow-software/</link><pubDate>Thu, 01 Aug 2019 22:11:07 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-08-01-what-is-a-workflow-software/</guid><description>&lt;p&gt;最近在思考是否应该仿照 ecFlow 重新实现一款业务系统流程调度软件，更专业的说法就是工作流软件。&lt;/p&gt;
&lt;p&gt;之前尝试过编写原始的流程调度软件，但已经很长时间没有更新。重复造轮子的事情总要想想意义何在。
目前数值预报中心一直使用 ECMWF 开发的业务系统调度软件，从 IBM 上的 SMS 到曙光-PI的 ecFlow，已形成完整的业务系统构建、运行和维护流程。
即便已使用工作流软件运行业务系统很多年，该软件也仅限于系统运行人员使用，没能取得更广泛的应用。
在同类软件已满足现有业务需求的情况下，重新编写一套仅有少数人使用的软件是否有意义？&lt;/p&gt;
&lt;p&gt;好在，今天看到的《“气候变化应对决策支撑系统工程”模式支撑软件系统开发（二期）》项目算是给出了一种答案。&lt;/p&gt;
&lt;p&gt;该项目是国家气象信息中心 2018 年公开招标的项目，中标公司是华云信息。招标文件可以从如下网址获取：&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.ccgp.gov.cn/cggg/zygg/zbgg/201810/t20181023_10948084.htm"&gt;http://www.ccgp.gov.cn/cggg/zygg/zbgg/201810/t20181023_10948084.htm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;该项目中的作业流程化运行管理分系统就是工作流软件。下面是项目技术规格及要求文件中对该子系统的总体描述。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;开发通用作业流程化运行管理系统，灵活可配置的构建模式运行的工作流，实现依赖关系的自动触发，可对数值预报模式系统进行分析研究，为其构建对应的工作流，并提供对工作流进行展示和运行监控等管理功能，实现模式作业的流程化调度运行和监控管理，实现数值预报系统的自动化可控运行。
实现模式通过作业流程化运行管理分系统提交任务，通过与 HPC 常用的作业管理软件 (如 LoadLeveler、Slurm 等) 的结合，使任务最终在高性能计算机系统上运行并反馈各类状态。
提供多种客户端，实现包括模式运行流程的灵活快速构建、模式作业的调度运行和控制、任务作业运行日志的采集与管理、多维可视化的监控和智能化故障告警等功能。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;该描述中包括对 ecFlow 等工作流软件通用功能的描述，对于工作流软件本身来讲，没有提出新的功能。
但该项目更强调与 HPC 结合，和对运维友好的各项功能 (日志分析、可视化监控、智能告警等)。
这些功能不是ecFlow等软件解决的主要问题，通常需要额外开发软件来实现。
该项目将这些功能整合到一个平台中，能大大降低数值预报模式业务系统运维人员的开发工作量。
不过一共 12 个月的开发周期让我有些担心成型软件最后的使用效果，毕竟 ecFlow 即将发布V5版本。
显然这不是我应该担心的，一套完整的作业流程运行管理系统可能更利于推广，还是值得应用的。&lt;/p&gt;
&lt;p&gt;更多功能模块的描述请参考招标文件，后面如果有时间我会详细介绍。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记：V5.0版本前瞻</title><link>https://blog.perillaroc.wang/post/2019/2019-06-21-ecflow-notebook-v5-preview/</link><pubDate>Fri, 21 Jun 2019 20:23:51 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-21-ecflow-notebook-v5-preview/</guid><description>&lt;blockquote&gt;
&lt;p&gt;2020.03 更新版&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;数值预报中心从去年开始使用 ECMWF 开发的 ecFlow 运行业务系统，目前使用 4.11.0 版本。
最近 ECMWF 召开用户大会，浏览了部分 PPT，发现在支撑工具方面ECMWF有明确的发展目标。&lt;/p&gt;
&lt;p&gt;ecFlow 官网已开源 V5.X 系列版本，目前最新版是 5.5。
在意大利的数据中心投入使用后，原有的 4.X 版本不再维护。&lt;/p&gt;
&lt;p&gt;本文简要介绍官网上列出的 &lt;a href="https://confluence.ecmwf.int/display/ECFLOW/ecflow+5+what%27s+new"&gt;5.0版特性&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="为什么要-50-版"&gt;为什么要 5.0 版&lt;/h2&gt;
&lt;p&gt;除了新增特性外，5.0 版最大的变动在于对底层的修改。&lt;/p&gt;
&lt;p&gt;4.X 版本依赖 boost serialisation 库实现客户端和服务器的交互，这就需要依赖固定版本的 boost 库，以满足 ecFlow 不同版本之间的兼容性。
从而使得扩展现有类的能力受到限制。
例如编译 ecFlow 4.X 版本时，一般采用 boost 1.53.0 版本。&lt;/p&gt;
&lt;p&gt;ecFlow 5.X 在客户端服务器通信中放弃对 boost 的依赖，现在使用 JSON 作为通讯数据。
因此未来的 ecFlow 5.X 可以使用不同版本的 boost 库。&lt;/p&gt;
&lt;p&gt;5.X 版本还缩短了客户端与服务器的通信延迟。&lt;/p&gt;
&lt;p&gt;为了支持创建 RPM 包而使用旧版本编译器，5.X 版本已放弃该功能。
ecFlow 需要至少支持 C++14 的编译器。&lt;/p&gt;
&lt;p&gt;现在 ecFlow 使用新版的 C++ 编译器和特性，提高软件的性能。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：GRIB2解码 - 处理JPEG2000压缩</title><link>https://blog.perillaroc.wang/post/2019/2019-06-07-grib-notebook-decode-grib2-jpeg-packing/</link><pubDate>Fri, 07 Jun 2019 16:07:12 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-07-grib-notebook-decode-grib2-jpeg-packing/</guid><description>&lt;p&gt;在之前的一些列文章中，我使用中国气象局数值预报中心GRAPES全球模式生成的GRIB2产品介绍GRIB2格式。接下来的一组文章会介绍如何解析GRAPES模式生成的GRIB2数据。&lt;/p&gt;
&lt;p&gt;尽管已有wgrib2、ecCodes等业务领域广泛应用的GRIB2文件编解码工具，自己实际编写一个GRIB2解码器有助于我更深入地了解GRIB2格式。&lt;/p&gt;
&lt;p&gt;简要研究过ecCodes及其前身grib api的源码，为了能解析任意GRIB2文件，大量代码用于处理GRIB2的表格和模板，整个项目的结构比较复杂。数值预报中心生成的GRIB2数据往往使用相同的表格和模板。对于手动编写解码程序，仅需要考虑一种情况。因此本系列文章仅关注固定表格、模板组合下的GRIB2数据解码。&lt;/p&gt;
&lt;p&gt;本文主要介绍GRIB2消息解码唯一需要外部库的部分：JPEG2000解码。&lt;/p&gt;
&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;数值预报中心的GRIB2数据都使用JPEG2000压缩，详情参见《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section5/"&gt;GRIB学习笔记：样例文件分析 - Section 5&lt;/a&gt;》。本文使用上面文章的样例数据进行说明。&lt;/p&gt;
&lt;p&gt;ecCodes中支持使用Jasper和OpenJPEG解码JPEG2000数据，本文选择OpenJPEG解码数据，并参考ecCodes中的代码。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ecmwf/eccodes/blob/develop/src/grib_openjpeg_encoding.c"&gt;grib_openjpeg_encoding.c&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="数据获取"&gt;数据获取&lt;/h2&gt;
&lt;p&gt;数据的描述放在Section 5，包括数据点个数，参考值，二进制因子和十进制因子等。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; binary_scale_factor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; decimal_scale_factor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;float&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;convertToFloat&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;uint32_t&lt;/span&gt; v) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;reinterpret_cast&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;float&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&amp;gt;&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;v));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;float&lt;/span&gt; reference_value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; convertToFloat(&lt;span style="color:#ae81ff"&gt;0x46B1298E&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我使用64位Windows 10的Visual Studio 2019编译程序，float是4字节浮点数，所以用float表示参考值。&lt;/p&gt;
&lt;p&gt;压缩后的数据放在Section 7，根据压缩的数据起始位置和终止位置，读取数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; start_pos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xB1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; raw_data_length &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0x98998&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0xB1&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; buf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;[raw_data_length];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;FILE&lt;span style="color:#f92672"&gt;*&lt;/span&gt; f &lt;span style="color:#f92672"&gt;=&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;fopen(grib_file_path.c_str(), &lt;span style="color:#e6db74"&gt;&amp;#34;rb&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;fseek(f, start_pos, SEEK_SET);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;fread(buf, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, raw_data_length, f);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;fclose(f);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="解码"&gt;解码&lt;/h2&gt;
&lt;p&gt;使用ecCodes的代码，使用OpenJPEG解码。需要三个输入数据：压缩后的数据及字节长度，原始数据个数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; decodeValues(&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; buf, size_t raw_data_length, size_t data_count) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;unsigned&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;long&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; val;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_dparameters_t parameters &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, };	&lt;span style="color:#75715e"&gt;/* decompression parameters */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_stream_t&lt;span style="color:#f92672"&gt;*&lt;/span&gt; stream &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_memory_stream mstream;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_image_t&lt;span style="color:#f92672"&gt;*&lt;/span&gt; image &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_codec_t&lt;span style="color:#f92672"&gt;*&lt;/span&gt; codec &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_image_comp_t comp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; { &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* set decoding parameters to default values */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_set_default_decoder_parameters(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;parameters);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	parameters.decod_format &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/* JP2_FMT */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* get a decoder handle */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	codec &lt;span style="color:#f92672"&gt;=&lt;/span&gt; opj_create_decompress(OPJ_CODEC_J2K);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* catch events using our callbacks and give a local context */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_set_info_handler(codec, openjpeg_info, &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_set_warning_handler(codec, openjpeg_warning, &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	opj_set_error_handler(codec, openjpeg_error, &lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* initialize our memory stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	mstream.pData &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buf;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	mstream.dataSize &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_data_length;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	mstream.offset &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* open a byte stream from memory stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	stream &lt;span style="color:#f92672"&gt;=&lt;/span&gt; opj_stream_create_default_memory_stream(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mstream, OPJ_STREAM_READ);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* setup the decoder decoding parameters using user parameters */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;opj_setup_decoder(codec, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;parameters)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;goto&lt;/span&gt; cleanup;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;opj_read_header(stream, codec, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;image)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;goto&lt;/span&gt; cleanup;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;opj_decode(codec, stream, image)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;goto&lt;/span&gt; cleanup;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;(data_count &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].w &lt;span style="color:#f92672"&gt;*&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].h)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;goto&lt;/span&gt; cleanup;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ((image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;numcomps &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; (image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;x1 &lt;span style="color:#f92672"&gt;*&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;y1) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;goto&lt;/span&gt; cleanup;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	_ASSERT(image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].sgnd &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	_ASSERT(comp.prec &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].data[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;); &lt;span style="color:#75715e"&gt;/* BR: -1 because I don&amp;#39;t know what happens if the sign bit is set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	_ASSERT(image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].prec &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;sizeof&lt;/span&gt;(mask) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].data;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	mask &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].prec) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; count &lt;span style="color:#f92672"&gt;=&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].w &lt;span style="color:#f92672"&gt;*&lt;/span&gt; image&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;comps[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;].h;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	val.resize(count);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; count; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;auto&lt;/span&gt; v &lt;span style="color:#f92672"&gt;=&lt;/span&gt; data[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		val[i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; v &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; mask;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;opj_end_decompress(codec, stream)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		err &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cleanup:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;/* close the byte stream */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (codec) opj_destroy_codec(codec);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (stream) opj_stream_destroy(stream);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (image) opj_image_destroy(image);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; val;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="还原数值"&gt;还原数值&lt;/h2&gt;
&lt;p&gt;解码得到的数据只是打包值，还需要根据公式还原原始数据。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 8</title><link>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section8/</link><pubDate>Sun, 02 Jun 2019 23:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section8/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-8-end-section"&gt;Section 8: End Section&lt;/h2&gt;
&lt;p&gt;结束段为四字节的“7777”。&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/8/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;7777&lt;/td&gt;
					&lt;td&gt;ascii&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;7777&amp;rdquo; (coded according to the International Alphabet No. 5.)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;====================== SECTION_8 ( length=4, padding=0 ) ======================
1-4 7777 = 7777
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;结束段为四字节的“7777”。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://cdn.perillaroc.wang/image/blog/2019/grib/section8.start.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;样例文件只有一条GRIB2消息。如果有下一条消息，以Section 0的四字节“GRIB”开始。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 7</title><link>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section7/</link><pubDate>Sun, 02 Jun 2019 22:00:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section7/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-7-data-section"&gt;Section 7: Data Section&lt;/h2&gt;
&lt;p&gt;包含数据值。GRIB2数据有多种压缩格式：简单封装、复杂封装、空间差分、JPEG2000、PNG等。。&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/7/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section7Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of section (7)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6-nn&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Data in a format described by Data Template 7.x, where x is the Data Representation Template number given in octets 10-11 of Section 5.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;====================== SECTION_7 ( length=624877, padding=0 ) ======================
1-4 section7Length = 624877
5 numberOfSection = 7
6-624877 codedValues = (1036800,624872) {
2.7052777344e+02, 2.7043777344e+02, 2.7054777344e+02, 2.7047777344e+02, 2.7043777344e+02, 2.7054777344e+02, 2.7046777344e+02, 2.7047777344e+02,
2.7048777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7049777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7048777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7048777344e+02, 2.7046777344e+02,
2.7048777344e+02, 2.7049777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7048777344e+02,
2.7047777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02,
2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02,
2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7046777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7045777344e+02,
2.7048777344e+02, 2.7046777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7046777344e+02,
2.7046777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7046777344e+02, 2.7048777344e+02,
2.7045777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7046777344e+02
... 1036700 more values
} # data_jpeg2000_packing codedValues
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;样例文件本节从 0xAC 开始&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 6</title><link>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section6/</link><pubDate>Sun, 02 Jun 2019 21:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section6/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-6-bit-map-section"&gt;Section 6: Bit-map Section&lt;/h2&gt;
&lt;p&gt;位图段用来指示紧邻的数据段的数据中每个网格点上的数据存在与否。用一位(1 bit)表示该网格点是否有数据，比对该点赋0值要节省很多空间。&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/6/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section6Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of section (6)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;bitMapIndicator&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Bit-map indicator (see Code Table 6.0 and Note 1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;7-nn&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Bit-map - Contiguous bits with a bit to data point correspondence, ordered as defined in Section 3. A bit set equal to 1 implies the presence of a data value at the corresponding data point, whereas a value of 0 implies the absence of such a value.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;====================== SECTION_6 ( length=6, padding=0 ) ======================
1-4 section6Length = 6
5 numberOfSection = 6
6 bitMapIndicator = 255 [A bit map does not apply to this product (grib2/tables/4/6.0.table) ]
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;样例文件本节从 0xA6 开始&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 5</title><link>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section5/</link><pubDate>Sun, 02 Jun 2019 16:30:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-02-grib-notebook-learn-by-sample-section5/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-5-data-representation-section"&gt;Section 5: Data Representation Section&lt;/h2&gt;
&lt;p&gt;定义如何解析下一个Data Section的数据。&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/5/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section5Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of section (5)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6-9&lt;/td&gt;
					&lt;td&gt;numberOfValues&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of data points where one or more values are specified in Section 7 when a bit map is present, total number of data points when a bit map is absent.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;10-11&lt;/td&gt;
					&lt;td&gt;dataRepresentationTemplateNumber&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Data Representation Template Number (see Code Table 5.0)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;12-nn&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Data Representation Template (see Template 5.x, where x is the Data Representation Template Number given in octets 10-11)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;====================== SECTION_5 ( length=23, padding=0 ) ======================
1-4 section5Length = 23
5 numberOfSection = 5
6-9 numberOfValues = 1036800
10-11 dataRepresentationTemplateNumber = 40 [JPEG2000 Packing (grib2/tables/4/5.0.table) ]
12-15 referenceValue = 22676.8
16-17 binaryScaleFactor = 0
18-19 decimalScaleFactor = 2
20 bitsPerValue = 13
21 typeOfOriginalFieldValues = 0 [Floating point (grib2/tables/4/5.1.table) ]
22 typeOfCompressionUsed = 0 [Lossless (grib2/tables/4/5.40.table) ]
23 targetCompressionRatio = 255
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;样例文件本节从 0x8f 开始&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 4</title><link>https://blog.perillaroc.wang/post/2019/2019-06-01-grib-notebook-learn-by-sample-section4/</link><pubDate>Sat, 01 Jun 2019 22:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-01-grib-notebook-learn-by-sample-section4/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-4-product-definition-section"&gt;Section 4: Product Definition Section&lt;/h2&gt;
&lt;p&gt;定义Section 5中数据的属性。&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/4/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section4Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned	Number of section (4)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6-7&lt;/td&gt;
					&lt;td&gt;NV&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of coordinate values after template or number of information according to 3D vertical coordinate GRIB2 message&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;8-9&lt;/td&gt;
					&lt;td&gt;productDefinitionTemplateNumber&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Product Definition Template Number (see Code Table 4.0)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;10-xx&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Product Definition Template (see Template 4.X, where X is the Product Definition Template Number given in octets 8-9)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;[xx+1]-nn&lt;/td&gt;
					&lt;td&gt;pv&lt;/td&gt;
					&lt;td&gt;ieeefloat&lt;/td&gt;
					&lt;td&gt;Optional list of coordinate values or vertical grid information&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;====================== SECTION_4 ( length=34, padding=0 ) ======================
1-4 section4Length = 34
5 numberOfSection = 4
6-7 NV = 0
8-9 productDefinitionTemplateNumber = 0 [Analysis or forecast at a horizontal level or in a horizontal layer at a point in time (grib2/tables/4/4.0.table) ]
10 parameterCategory = 0 [Temperature (grib2/tables/4/4.1.0.table) ]
11 parameterNumber = 0 [Temperature (K) (grib2/tables/4/4.2.0.0.table) ]
12 typeOfGeneratingProcess = 0 [Analysis (grib2/tables/4/4.3.table) ]
13 backgroundProcess = 0
14 generatingProcessIdentifier = 15
15-16 hoursAfterDataCutoff = 0
17 minutesAfterDataCutoff = 0
18 indicatorOfUnitOfTimeRange = 1 [Hour (grib2/tables/4/4.4.table) ]
19-22 forecastTime = 0
23 typeOfFirstFixedSurface = 100 [Isobaric surface (Pa) (grib2/tables/4/4.5.table) ]
24 scaleFactorOfFirstFixedSurface = 0
25-28 scaledValueOfFirstFixedSurface = 85000
29 typeOfSecondFixedSurface = 255 [Missing (grib2/tables/4/4.5.table) ]
30 scaleFactorOfSecondFixedSurface = MISSING
31-34 scaledValueOfSecondFixedSurface = MISSING
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;1-4: section长度&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 3</title><link>https://blog.perillaroc.wang/post/2019/2019-06-01-grib-notebook-learn-by-sample-section3/</link><pubDate>Sat, 01 Jun 2019 19:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-06-01-grib-notebook-learn-by-sample-section3/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-3-grid-definition-section"&gt;Section 3: Grid Definition Section&lt;/h2&gt;
&lt;p&gt;定义数据的网格表面和几何形状，&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/3/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section3Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of section (3)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;sourceOfGridDefinition&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Source of grid definition (see Code Table 3.0 and Note 1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;7-10&lt;/td&gt;
					&lt;td&gt;numberOfDataPoints&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of data points&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;11&lt;/td&gt;
					&lt;td&gt;numberOfOctectsForNumberOfPoints&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of octets for optional list of numbers (see Note 2)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;12&lt;/td&gt;
					&lt;td&gt;interpretationOfNumberOfPoints&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Interpretation of list of numbers (see Code Table 3.11)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;13-14&lt;/td&gt;
					&lt;td&gt;gridDefinitionTemplateNumber&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Grid Definition Template Number (= N) (see Code Table 3.1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;15-xx&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Grid Definition Template (see Template 3.N, where N is the Grid Definition Template Number given in octets 13-14)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;[xx+1]-nn&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Optional list of numbers defining number of points (see Notes 2, 3 and 4)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;用可选的格点列表来表示不规则的网格点，附加在规则网格模板点的后面。数值预报中心只用规则网格。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 2</title><link>https://blog.perillaroc.wang/post/2019/2019-05-30-grib-notebook-learn-by-sample-section2/</link><pubDate>Thu, 30 May 2019 21:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-30-grib-notebook-learn-by-sample-section2/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-2-local-use-section"&gt;Section 2: Local Use Section&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/2/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section2Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of section (2)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6-nn&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Local use&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;数值预报中心尚未使用Section 2，样例文件中也没有Section 2，省略此部分。&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 1</title><link>https://blog.perillaroc.wang/post/2019/2019-05-29-grib-notebook-learn-by-sample-section1/</link><pubDate>Wed, 29 May 2019 21:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-29-grib-notebook-learn-by-sample-section1/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-1-identification-section"&gt;Section 1: Identification Section&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/1/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;section1Length&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Length of section in octets (21 or nn)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;numberOfSection&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Number of section (1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6-7&lt;/td&gt;
					&lt;td&gt;centre&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Identification of originating/generating centre (see Common Code Table C-11)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;8-9&lt;/td&gt;
					&lt;td&gt;subCentre&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Identification of originating/generating sub-centre (allocated by originating/generating Centre)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;10&lt;/td&gt;
					&lt;td&gt;tablesVersion&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;GRIB Master Tables Version Number (see Code Table 1.0 and Note 1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;11&lt;/td&gt;
					&lt;td&gt;localTablesVersion&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Version number of GRIB Local Tables used to augment Master Tables (see Code Table 1.1 and Note 2)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;12&lt;/td&gt;
					&lt;td&gt;significanceOfReferenceTime&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Significance of Reference Time (see Code Table 1.2)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;13-14&lt;/td&gt;
					&lt;td&gt;year&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Year (4 digits)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;15&lt;/td&gt;
					&lt;td&gt;month&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Month&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;16&lt;/td&gt;
					&lt;td&gt;day&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Day&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;17&lt;/td&gt;
					&lt;td&gt;hour&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Hour&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;18&lt;/td&gt;
					&lt;td&gt;minute&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Minute&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;19&lt;/td&gt;
					&lt;td&gt;second&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Second&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;20&lt;/td&gt;
					&lt;td&gt;productionStatusOfProcessedData&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Production status of processed data in this GRIB message (see Code Table 1.3)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;21&lt;/td&gt;
					&lt;td&gt;typeOfProcessedData&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Type of processed data in this GRIB message (see Code Table 1.4)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;22 - 23&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Identification template number (optional, see Code table 1.5)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;24 - nn&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;Identification template (optional, see template 1.X, where X is the identification template number given in octets 22-23)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;====================== SECTION_1 ( length=21, padding=0 ) ======================
1-4 section1Length = 21
5 numberOfSection = 1
6-7 centre = 38 [Beijing (RSMC) (grib2/centre.table) ]
8-9 subCentre = 0
10 tablesVersion = 4 [Version implemented on 7 November 2007 (grib2/tables/1.0.table) ]
11 localTablesVersion = 1 [Unknown code table entry (grib2/tables/4/1.1.table) ]
12 significanceOfReferenceTime = 0 [Analysis (grib2/tables/4/1.2.table) ]
13-14 year = 2019
15 month = 5
16 day = 27
17 hour = 0
18 minute = 0
19 second = 0
20 productionStatusOfProcessedData = 0 [Operational products (grib2/tables/4/1.3.table) ]
21 typeOfProcessedData = 0 [Analysis products (grib2/tables/4/1.4.table) ]
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;1-4：section长度
5：section序号&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - Section 0</title><link>https://blog.perillaroc.wang/post/2019/2019-05-28-grib-notebook-learn-by-sample-section0/</link><pubDate>Tue, 28 May 2019 21:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-28-grib-notebook-learn-by-sample-section0/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="section-0-indicator-section"&gt;Section 0: Indicator Section&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://apps.ecmwf.int/codes/grib/format/grib2/sections/0/"&gt;内容如下&lt;/a&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Octets&lt;/th&gt;
					&lt;th&gt;Key&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1-4&lt;/td&gt;
					&lt;td&gt;identifier&lt;/td&gt;
					&lt;td&gt;ascii&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;GRIB&amp;rdquo; (coded according to the International Alphabet No. 5.)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5-6&lt;/td&gt;
					&lt;td&gt;reserved&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Reserved&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;7&lt;/td&gt;
					&lt;td&gt;discipline&lt;/td&gt;
					&lt;td&gt;codetable&lt;/td&gt;
					&lt;td&gt;Discipline - GRIB Master Table Number (see Code Table 0.0)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;8&lt;/td&gt;
					&lt;td&gt;editionNumber&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;GRIB Edition Number (currently 2)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;9-16&lt;/td&gt;
					&lt;td&gt;totalLength&lt;/td&gt;
					&lt;td&gt;unsigned&lt;/td&gt;
					&lt;td&gt;Total length of GRIB message in octets (including Section 0)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="grib_dump示例"&gt;grib_dump示例&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#============== MESSAGE 1 ( length=625053 ) ==============
1-4 identifier = GRIB
5-6 reserved = MISSING
7 discipline = 0 [Meteorological products (grib2/tables/4/0.0.table) ]
8 editionNumber = 2
9-16 totalLength = 625053
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;1-4：四字节的起始字段，内容是GRIB，如图：&lt;/p&gt;</description></item><item><title>GRIB学习笔记：样例文件分析 - 概要</title><link>https://blog.perillaroc.wang/post/2019/2019-05-27-grib-notebook-learn-by-sample-intro/</link><pubDate>Mon, 27 May 2019 21:05:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-27-grib-notebook-learn-by-sample-intro/</guid><description>&lt;p&gt;本文通过分析一个GRIB2消息介绍GRIB2格式。&lt;/p&gt;
&lt;p&gt;样例文件来自中国气象局数值预报中心GRAPES全球模式的预报结果，选用2019年5月26日00时次的000时次850hPa温度场。&lt;/p&gt;
&lt;h2 id="grib2消息概要"&gt;GRIB2消息概要&lt;/h2&gt;
&lt;p&gt;使用&lt;code&gt;grib_dump&lt;/code&gt;查看该样例文件包含哪些信息&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;***** FILE: t.850hpa.000.grb2
#============== MESSAGE 1 ( length=625053 ) ==============
1-4 identifier = GRIB
5-6 reserved = MISSING
7 discipline = 0 [Meteorological products (grib2/tables/4/0.0.table) ]
8 editionNumber = 2
9-16 totalLength = 625053
====================== SECTION_1 ( length=21, padding=0 ) ======================
1-4 section1Length = 21
5 numberOfSection = 1
6-7 centre = 38 [Beijing (RSMC) (grib2/centre.table) ]
8-9 subCentre = 0
10 tablesVersion = 4 [Version implemented on 7 November 2007 (grib2/tables/1.0.table) ]
11 localTablesVersion = 1 [Unknown code table entry (grib2/tables/4/1.1.table) ]
12 significanceOfReferenceTime = 0 [Analysis (grib2/tables/4/1.2.table) ]
13-14 year = 2019
15 month = 5
16 day = 27
17 hour = 0
18 minute = 0
19 second = 0
20 productionStatusOfProcessedData = 0 [Operational products (grib2/tables/4/1.3.table) ]
21 typeOfProcessedData = 0 [Analysis products (grib2/tables/4/1.4.table) ]
====================== SECTION_3 ( length=72, padding=0 ) ======================
1-4 section3Length = 72
5 numberOfSection = 3
6 sourceOfGridDefinition = 0 [Specified in Code table 3.1 (grib2/tables/4/3.0.table) ]
7-10 numberOfDataPoints = 1036800
11 numberOfOctectsForNumberOfPoints = 0
12 interpretationOfNumberOfPoints = 0 [There is no appended list (grib2/tables/4/3.11.table) ]
13-14 gridDefinitionTemplateNumber = 0 [Latitude/longitude (Also called equidistant cylindrical, or Plate Carree) (grib2/tables/4/3.1.table) ]
15 shapeOfTheEarth = 6 [Earth assumed spherical with radius of 6,371,229.0 m (grib2/tables/4/3.2.table) ]
16 scaleFactorOfRadiusOfSphericalEarth = 0
17-20 scaledValueOfRadiusOfSphericalEarth = 0
21 scaleFactorOfEarthMajorAxis = 0
22-25 scaledValueOfEarthMajorAxis = 0
26 scaleFactorOfEarthMinorAxis = 0
27-30 scaledValueOfEarthMinorAxis = 0
31-34 Ni = 1440
35-38 Nj = 720
39-42 basicAngleOfTheInitialProductionDomain = 0
43-46 subdivisionsOfBasicAngle = 0
47-50 latitudeOfFirstGridPoint = 89875000
51-54 longitudeOfFirstGridPoint = 0
55 resolutionAndComponentFlags = 48 [00110000]
56-59 latitudeOfLastGridPoint = -89875000
60-63 longitudeOfLastGridPoint = 359750000
64-67 iDirectionIncrement = 250000
68-71 jDirectionIncrement = 250000
72 scanningMode = 0 [00000000]
====================== SECTION_4 ( length=34, padding=0 ) ======================
1-4 section4Length = 34
5 numberOfSection = 4
6-7 NV = 0
8-9 productDefinitionTemplateNumber = 0 [Analysis or forecast at a horizontal level or in a horizontal layer at a point in time (grib2/tables/4/4.0.table) ]
10 parameterCategory = 0 [Temperature (grib2/tables/4/4.1.0.table) ]
11 parameterNumber = 0 [Temperature (K) (grib2/tables/4/4.2.0.0.table) ]
12 typeOfGeneratingProcess = 0 [Analysis (grib2/tables/4/4.3.table) ]
13 backgroundProcess = 0
14 generatingProcessIdentifier = 15
15-16 hoursAfterDataCutoff = 0
17 minutesAfterDataCutoff = 0
18 indicatorOfUnitOfTimeRange = 1 [Hour (grib2/tables/4/4.4.table) ]
19-22 forecastTime = 0
23 typeOfFirstFixedSurface = 100 [Isobaric surface (Pa) (grib2/tables/4/4.5.table) ]
24 scaleFactorOfFirstFixedSurface = 0
25-28 scaledValueOfFirstFixedSurface = 85000
29 typeOfSecondFixedSurface = 255 [Missing (grib2/tables/4/4.5.table) ]
30 scaleFactorOfSecondFixedSurface = MISSING
31-34 scaledValueOfSecondFixedSurface = MISSING
====================== SECTION_5 ( length=23, padding=0 ) ======================
1-4 section5Length = 23
5 numberOfSection = 5
6-9 numberOfValues = 1036800
10-11 dataRepresentationTemplateNumber = 40 [JPEG2000 Packing (grib2/tables/4/5.0.table) ]
12-15 referenceValue = 22676.8
16-17 binaryScaleFactor = 0
18-19 decimalScaleFactor = 2
20 bitsPerValue = 13
21 typeOfOriginalFieldValues = 0 [Floating point (grib2/tables/4/5.1.table) ]
22 typeOfCompressionUsed = 0 [Lossless (grib2/tables/4/5.40.table) ]
23 targetCompressionRatio = 255
====================== SECTION_6 ( length=6, padding=0 ) ======================
1-4 section6Length = 6
5 numberOfSection = 6
6 bitMapIndicator = 255 [A bit map does not apply to this product (grib2/tables/4/6.0.table) ]
====================== SECTION_7 ( length=624877, padding=0 ) ======================
1-4 section7Length = 624877
5 numberOfSection = 7
6-624877 codedValues = (1036800,624872) {
2.7052777344e+02, 2.7043777344e+02, 2.7054777344e+02, 2.7047777344e+02, 2.7043777344e+02, 2.7054777344e+02, 2.7046777344e+02, 2.7047777344e+02,
2.7048777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7049777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7048777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7048777344e+02, 2.7046777344e+02,
2.7048777344e+02, 2.7049777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7048777344e+02,
2.7047777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7047777344e+02, 2.7048777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02,
2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02,
2.7047777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7047777344e+02,
2.7046777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7046777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7045777344e+02,
2.7048777344e+02, 2.7046777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7048777344e+02, 2.7046777344e+02,
2.7046777344e+02, 2.7047777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7046777344e+02, 2.7048777344e+02,
2.7045777344e+02, 2.7047777344e+02, 2.7046777344e+02, 2.7046777344e+02
... 1036700 more values
} # data_jpeg2000_packing codedValues
====================== SECTION_8 ( length=4, padding=0 ) ======================
1-4 7777 = 7777
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从上面的输出结果可以看到，GRIB2消息包含9个部分（section 0~8）。下面结合样例文件中介绍每个section的具体内容。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记04：使用C++ API</title><link>https://blog.perillaroc.wang/post/2019/2019-05-26-ecflow-notebook-using-cpp-api/</link><pubDate>Sun, 26 May 2019 17:38:58 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-26-ecflow-notebook-using-cpp-api/</guid><description>&lt;p&gt;ecFlow提供命令行和Python API两种方式交互方式，命令行适合加载、替换、删除系统等操作，Python API适合进行二次开发。但Python API的局限在于必须编译ecFlow源码才能得到ecFlow的Python包，不支持&lt;code&gt;pip&lt;/code&gt;等包安装器，部署二次开发的应用非常繁琐。&lt;/p&gt;
&lt;p&gt;为了封装ecFlow的Python API，我开发了&lt;a href="https://github.com/perillaroc/ecflow-docker"&gt;ecflow-docker&lt;/a&gt;，构建Docker镜像时编译ecFlow源码。&lt;/p&gt;
&lt;p&gt;既然ecFlow使用Boost Python封装Python接口，我们可以直接使用c++ API与ecFlow交互。虽然这不是官方推荐的方式，但使用c++接口二次开发的应用更方便部署（使用静态链接库，直接拷贝二进制程序）。下面介绍如何使用ecFlow的c++ API。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;ecFlow客户端中使用&lt;code&gt;ClientInvoker&lt;/code&gt;与ecFlow服务通讯，使用&lt;code&gt;Defs&lt;/code&gt;描述整个服务的节点树。&lt;/p&gt;
&lt;p&gt;调用&lt;code&gt;ClientInvoker&lt;/code&gt;的&lt;code&gt;sync_local&lt;/code&gt;方法，可以获取节点树的当前状态。&lt;/p&gt;
&lt;h2 id="链接"&gt;链接&lt;/h2&gt;
&lt;p&gt;使用cmake编译ecFlow后，会有两个目录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ECFLOW_SOURCE_DIR&lt;/code&gt;：ecFlow源码目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECFLOW_BUILD_DIR&lt;/code&gt;：ecFlow编译目录，包含生成的静态库文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了调用ecFlow的c++ API，需要设置头文件包含路径和连接库。下面的代码构造ecFlow的cmake接口库目标，为其他构建目标提供头文件路径和链接库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmake" data-lang="cmake"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;if(&lt;span style="color:#e6db74"&gt;NOT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;ECFLOW_BUILD_DIR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;OR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;NOT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;ECFLOW_SOURCE_DIR&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message(&lt;span style="color:#e6db74"&gt;FATAL_ERROR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Please set ECFLOW_BUILD_DIR and ECFLOW_SOURCE_DIR&amp;#34;&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;endif()&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add_library(&lt;span style="color:#e6db74"&gt;Ecflow&lt;/span&gt; &lt;span style="color:#e6db74"&gt;INTERFACE&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target_include_directories(&lt;span style="color:#e6db74"&gt;Ecflow&lt;/span&gt; &lt;span style="color:#e6db74"&gt;INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/ACore/src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/ANattr/src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/ANode/src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/Base/src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/Base/src/cts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/Base/src/stc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/CSim/src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_SOURCE_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/Client/src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target_link_libraries(&lt;span style="color:#e6db74"&gt;Ecflow&lt;/span&gt; &lt;span style="color:#e6db74"&gt;INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_BUILD_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/Client/liblibclient.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_BUILD_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/Base/libbase.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_BUILD_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/CSim/liblibsimu.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_BUILD_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/ANode/libnode.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_BUILD_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/ANattr/libnodeattr.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;${&lt;/span&gt;ECFLOW_BUILD_DIR&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/ACore/libcore.a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add_library(&lt;span style="color:#e6db74"&gt;Ecflow::Ecflow&lt;/span&gt; &lt;span style="color:#e6db74"&gt;ALIAS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;Ecflow&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其他构建目标需要链接该接口，同时需要链接Boost库。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmake" data-lang="cmake"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;add_library(&lt;span style="color:#e6db74"&gt;ecflow_util&lt;/span&gt; &lt;span style="color:#e6db74"&gt;STATIC&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target_sources(&lt;span style="color:#e6db74"&gt;ecflow_util&lt;/span&gt; &lt;span style="color:#e6db74"&gt;PRIVATE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;src/ecflow_client.cpp&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target_include_directories(&lt;span style="color:#e6db74"&gt;ecflow_util&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;PUBLIC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;$&amp;lt;&lt;/span&gt;INSTALL_INTERFACE:include&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;$&amp;lt;&lt;/span&gt;BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target_link_libraries(&lt;span style="color:#e6db74"&gt;ecflow_util&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;PUBLIC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;workflow_model&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;PRIVATE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Ecflow::Ecflow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;INTERFACE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::system&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::filesystem&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::date_time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::program_options&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::serialization&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::thread&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;Boost::regex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="接口"&gt;接口&lt;/h2&gt;
&lt;p&gt;使用下面的代码，可以获取ecFlow所有节点的运行状态：&lt;/p&gt;</description></item><item><title>为Golang应用程序添加编译信息</title><link>https://blog.perillaroc.wang/post/2019/2019-05-23-add-building-info-for-golang-application/</link><pubDate>Fri, 24 May 2019 21:10:51 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-23-add-building-info-for-golang-application/</guid><description>&lt;p&gt;C语言提供预处理器宏供用户在编译期间提供信息，同时内置&lt;code&gt;__FILE__&lt;/code&gt;、&lt;code&gt;__TIME__&lt;/code&gt;等宏。&lt;/p&gt;
&lt;p&gt;Golang中没有宏，但我们可以使用&lt;code&gt;go tool link [flags]&lt;/code&gt;提供的选项&lt;code&gt;-X&lt;/code&gt;实现类似的功能。&lt;/p&gt;
&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;-X&lt;/code&gt;选项说明如下&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-X importpath.name=value
	Set the value of the string variable in importpath named name to value.
	This is only effective if the variable is declared in the source code either uninitialized
	or initialized to a constant string expression. -X will not work if the initializer makes
	a function call or refers to other variables.
	Note that before Go 1.5 this option took two separate arguments.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;该选项将某个字符串变量&lt;code&gt;importpath.name&lt;/code&gt;的值设置为&lt;code&gt;value&lt;/code&gt;。该变量需要满足下面两个条件之一：&lt;/p&gt;</description></item><item><title>D3.js学习笔记：绘制等值线图</title><link>https://blog.perillaroc.wang/post/2019/2019-05-19-d3-notebook-draw-contour/</link><pubDate>Sun, 19 May 2019 16:01:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-19-d3-notebook-draw-contour/</guid><description>&lt;p&gt;D3.js的5.X版本新增&lt;code&gt;d3-contour&lt;/code&gt;组件，支持绘制等值线图。本文介绍使用&lt;code&gt;d3-contour&lt;/code&gt;绘制气象要素等值线图的方法。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;使用等经纬度网格的气象要素场，使用《&lt;a href="https://blog.perillaroc.wang/post/2019/2019-05-18-grib-notebook-convert-grib2-to-png/"&gt;GRIB2要素场转换为图片&lt;/a&gt;》介绍的方法，通过图片加载数据。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;fetch&lt;/code&gt;加载图片和描述文件，使用&lt;code&gt;jimp&lt;/code&gt;获取图片像素值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Promise.&lt;span style="color:#a6e22e"&gt;all&lt;/span&gt;([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Jimp&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;read&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;public/data/t.png&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;public/data/t.json&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]).&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;values&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data_image&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;metadata_response&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metadata_response&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;then&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data_image&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;bitmap&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;index&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;real_values&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;max_value&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;min_value&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;min_value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// continue to draw contours
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码使用描述文件中的信息将图像灰度值数组&lt;code&gt;values&lt;/code&gt;恢复为数据实际值数组&lt;code&gt;real_values&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="绘制等值线填充图"&gt;绘制等值线填充图&lt;/h2&gt;
&lt;p&gt;在svg上绘制等值线，创建svg节点，指定宽度和高度。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;width&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1600.&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;height&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;800.&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;svg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;select&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;#page&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;svg&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;width&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;height&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;height&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;d3.ticks&lt;/code&gt;构建等值线的间隔，并为每个间隔分配一个颜色。这里我将最大值最小值区间等分为20分，使用&lt;code&gt;d3.interpolateMagma&lt;/code&gt;色表。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;thresholds&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ticks&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;min_value&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;max_value&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;scaleSequential&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;interpolateMagma&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;domain&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;extent&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;thresholds&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;d3.contours&lt;/code&gt;构建等值线，设置数据矩阵的行宽和列宽，设置等值线间隔，使用实际的数据值生成等值线对象。返回的结果是GeoJSON的数组，每个元素代表一个间隔的等值线。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;contours&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;contours&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;size&lt;/span&gt;([&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;nx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ny&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;thresholds&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;thresholds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#a6e22e"&gt;real_values&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;d3.geoPath&lt;/code&gt;绘制等值线。这里我将每层的颜色赋值给&lt;code&gt;path&lt;/code&gt;的&lt;code&gt;fill&lt;/code&gt;属性，用于绘制填充图。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;contour_g&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;svg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;g&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;contour_g&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;selectAll&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;.contour&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;contours&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;enter&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;class&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;contour&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;d&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;geoPath&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;fill&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;) { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;); });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;显示效果如下图所示&lt;/p&gt;</description></item><item><title>GRIB学习笔记：GRIB2要素场转换为图片</title><link>https://blog.perillaroc.wang/post/2019/2019-05-18-grib-notebook-convert-grib2-to-png/</link><pubDate>Sat, 18 May 2019 17:20:59 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-18-grib-notebook-convert-grib2-to-png/</guid><description>&lt;p&gt;Web实时显示气象要素场一般有两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预先生成图片，叠加在底图上&lt;/li&gt;
&lt;li&gt;加载远程数据，本地绘图&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文主要介绍第二个方法中加载远程数据的一种方法。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;GRIB2消息中保存的要素场一般使用JPEG压缩，我们常用的网格是等经纬度网格，数据是一个矩阵形式，因此GRIB2消息中的数据可以看成一张常规的图片。尽管目前尚缺乏有效的解码GRIB2数据的JavaScript库，但我们可以将GRIB2数据转成图片格式传给Web客户端，以图片的方式传递数据。&lt;/p&gt;
&lt;h2 id="数据转换"&gt;数据转换&lt;/h2&gt;
&lt;p&gt;将GRIB2要素场转换为图片，需要考虑如何转换实际数据为图片像素点的颜色值。&lt;/p&gt;
&lt;p&gt;我们可以借鉴GRIB2存储数据的方式。为了保证数据的经度，GRIB2的数据段保存的不是实际的数据信息，而是使用一个公式计算后的结果。GRIB2数据的&lt;a href="//www.wmo.int/pages/prog/www/WDM/Guides/Guide-binary-2.html"&gt;计算公式&lt;/a&gt;如下：&lt;/p&gt;
&lt;p&gt;$$Y*D^{10}=R+(X1+X2)*2^E$$&lt;/p&gt;
&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Y：原始值&lt;/li&gt;
&lt;li&gt;D：十进制比例因子，为了获得需要的精确度。有符号十六位整数&lt;/li&gt;
&lt;li&gt;R：参考值，32位浮点数&lt;/li&gt;
&lt;li&gt;X：内部值，每个记录有自己的位数&lt;/li&gt;
&lt;li&gt;E：二进制比例因子，用于变长字长打包，有符号十六位整数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个数据点只有Y和X值不同，所以数据段只存储X值，其他数值保存在数据描述段。&lt;/p&gt;
&lt;p&gt;上面的公式比较复杂，在线绘图一般不需要很高的精度，所以可以将上面的公式简化。为了将数据转换为灰度图，将最大值最小值区间分成256份，每个数据值映射到这256个子区间。简化后的公式如下所示：&lt;/p&gt;
&lt;p&gt;$$Y=(M_{2}-M_{1})*X/255+M_{1}$$&lt;/p&gt;
&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Y：原始值，浮点数&lt;/li&gt;
&lt;li&gt;M1：数据最小值，浮点数&lt;/li&gt;
&lt;li&gt;M2：数据最大值，浮点数&lt;/li&gt;
&lt;li&gt;X：像素点灰度值，整形&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用上述公式，就可以将GRIB2数据转为一张与网格大小相同的灰度图像。为了恢复原始数据，还需要知道M1，M2的值，因此将这些信息写入一个单独的JSON文件，与数据一同发送给客户端，由客户端负责从灰度值恢复原始数据。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;使用&lt;code&gt;nuwe_pyeccodes&lt;/code&gt;获取GRIB2要素场。下面代码中&lt;code&gt;message_handler&lt;/code&gt;代表一个要素场。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;left_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;right_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lon_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;iDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getLong(&lt;span style="color:#e6db74"&gt;&amp;#39;Ni&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;top_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bottom_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lat_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;jDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ny &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getLong(&lt;span style="color:#e6db74"&gt;&amp;#39;Nj&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; message_handler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDoubleArray(&lt;span style="color:#e6db74"&gt;&amp;#39;values&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; values&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reshape(ny, nx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;min_value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max(values)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;max_value &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;min(values)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; (values &lt;span style="color:#f92672"&gt;-&lt;/span&gt; min_value) &lt;span style="color:#f92672"&gt;/&lt;/span&gt; (max_value&lt;span style="color:#f92672"&gt;-&lt;/span&gt;min_value) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;255&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;PIL&lt;/code&gt;生成图片文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; PIL &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Image
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Image&lt;span style="color:#f92672"&gt;.&lt;/span&gt;fromarray(values)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im &lt;span style="color:#f92672"&gt;=&lt;/span&gt; im&lt;span style="color:#f92672"&gt;.&lt;/span&gt;convert(&lt;span style="color:#e6db74"&gt;&amp;#34;L&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;im&lt;span style="color:#f92672"&gt;.&lt;/span&gt;save(&lt;span style="color:#e6db74"&gt;&amp;#34;t.png&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成对应的JSON描述文件&lt;/p&gt;</description></item><item><title>数值预报业务系统的归档目录设计</title><link>https://blog.perillaroc.wang/post/2019/2019-05-09-nwp-notebook-archive-directory-structure/</link><pubDate>Thu, 09 May 2019 19:44:36 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-09-nwp-notebook-archive-directory-structure/</guid><description>&lt;p&gt;去年，单位在迁移数值预报业务系统时重新设计了业务系统数据的归档存储目录。由过去每个系统都有各自的归档目录结构改成统一的结构。&lt;/p&gt;
&lt;p&gt;今年对目录结构进行了微调，将归档根目录从用户数据目录(/g2/nwp/OPER_ARCH_TEST)迁移到系统公用目录(/g1/COMMONDATA/)。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;数据的归档路径主要包括下面几个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单位名称，区别不同业务单位，例如NWPC表示中国气象局数值预报中心等。&lt;/li&gt;
&lt;li&gt;模式，大部分模式都只有一级目录，例如&lt;code&gt;GRAPES_GFS_GMF&lt;/code&gt;，少部分模式可能有多级目录。&lt;/li&gt;
&lt;li&gt;数据种类，对于不同的模式系统，每种类型数据有相同的名字。&lt;/li&gt;
&lt;li&gt;起报时次，时间维度。&lt;/li&gt;
&lt;li&gt;数据子类别，可选，由模式系统开发人员自己确定。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下图展示GRAPES GFS模式积分postvar数据如何保存到归档目录中：&lt;/p&gt;
&lt;p&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="561px" height="241px" viewBox="-0.5 -0.5 561 241" content="&amp;lt;mxfile modified=&amp;quot;2019-08-14T23:27:03.149Z&amp;quot; host=&amp;quot;www.draw.io&amp;quot; agent=&amp;quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36&amp;quot; etag=&amp;quot;Q2wbJsfRzkak7LWqYdps&amp;quot; version=&amp;quot;11.1.4&amp;quot; type=&amp;quot;onedrive&amp;quot;&amp;gt;&amp;lt;diagram id=&amp;quot;ENXLom_mKNOw8PK7sTyr&amp;quot; name=&amp;quot;第 1 页&amp;quot;&amp;gt;7ZhNb6MwEIZ/jY+RwIADRyCQHpq2alaqtJeKgvnQGpwFp0n3169tTBICq+welvaA1Erjd4zN+PGYiYHhl8d1He3yDU0wAVBLjsBYAQh1E0Ig/rTko1WWyGqFrC4S1eksbItfWImaUvdFgpteR0YpYcWuL8a0qnDMelpU1/TQ75ZS0p91F2V4IGzjiAzVlyJhuVJ15Jwdd7jIcjW1DZeto4y6ziqSJo8SeriQjAAYfk0pa63y6GMiFq9bl/a58A/e04vVuGJ/88DrnfG8SN2X73dlefzpLBrd/bVQdN4jslcBA4gIH89rdlHF7UzYfNCMzxf6j5vN48PK/ebyxuNT8CxmU/252X9Exsw+uoWs6b5KsHgXjbsPecHwdhfFwnvgW4drOSsJb+ncTGnFwqgsiNg19/u4SCI+mk+rhorxpF/tFR3xdkSKrOINglMxeVoQ4lNCazm1kVjYTkwRE6vpD3zhseGbgVAbbVxU2b18Xr6hUsQM1imey9VWAN5xzfDxQlKrv8a0xKz+4F2UF5pqJ6hUsFXzcN5XZtclv9hSnRaprZydRj7T5oYC/g/wjQH8h5cnfyY3JGf3yelwBJ02JTpzgG797D4F29d1yP83oUzMmeMVRwNecURDjgaakqM14BjGDVsQyuOeEY4hRH2EUBtBCKdEiAYIoaY7mqXZIpSZ4ZDh6ajsGJpDhqcjdxKGywHDHW3Ye1QrlI6mverInlkOWV4VNWNVDZy0qrGHJW1gAW8FHG4g4OrANaShAc8BwRI4HnCDro/1OYzrdmGuIadpCuN4DHKC3pA1FWQd3qxc9UnPXGeUsS35BaYAaa9mkCMg0e1CdlqS3e/8HkqenLZIVJGTPrBDkaWeATxPGh5wPumr+rXhQu12dTsxXH0ULk9STxMGT1Jx8nKmuoRrAScA9ifdHXxxuNff2ZG6d2K4I3dHgQ08Dncp4brAtSRuzhfJpPZFUs9wb94vjBXEE8Md3g2NZS5XuL2U31xPUJ7h3rx0+J/VE2+eL5Sl7+Ja3gh+Aw==&amp;lt;/diagram&amp;gt;&amp;lt;/mxfile&amp;gt;" style="background-color: rgb(255, 255, 255);"&gt;&lt;defs/&gt;&lt;g&gt;&lt;rect x="120" y="0" width="440" height="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/&gt;&lt;g transform="translate(135.5,11.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="193" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 194px; white-space: nowrap; overflow-wrap: normal; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;&lt;span&gt;/g1/COMMONDATA/OPER/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="97" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;&amp;lt;span&amp;gt;/g1/COMMONDATA/OPER/&amp;lt;/span&amp;gt;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="160" y="40" width="400" height="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/&gt;&lt;g transform="translate(175.5,51.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="39" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 40px; white-space: nowrap; overflow-wrap: normal; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;NWPC&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="20" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;NWPC&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="200" y="80" width="360" height="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/&gt;&lt;g transform="translate(215.5,91.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="145" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 146px; white-space: nowrap; overflow-wrap: normal; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;GRAPES_GFS_GMF/&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="73" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;GRAPES_GFS_GMF/&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="240" y="120" width="320" height="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/&gt;&lt;g transform="translate(255.5,131.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="97" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 98px; white-space: nowrap; overflow-wrap: normal; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;Fcst-long/&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="49" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;Fcst-long/&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="280" y="160" width="280" height="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/&gt;&lt;g transform="translate(295.5,171.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="106" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 107px; white-space: nowrap; overflow-wrap: normal; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;2019050821/&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="53" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;2019050821/&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="320" y="200" width="240" height="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/&gt;&lt;g transform="translate(335.5,211.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="203" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 204px; white-space: nowrap; overflow-wrap: normal; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;postvar2019050900_168&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="102" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;postvar2019050900_168&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="0" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(23.5,11.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="80" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 81px; white-space: nowrap; overflow-wrap: normal; text-align: right;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;归档根目录&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="40" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;归档根目录&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="40" y="40" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(111.5,51.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="32" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 33px; white-space: nowrap; overflow-wrap: normal; text-align: right;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;单位&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="16" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;单位&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="80" y="80" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(119.5,91.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="64" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 65px; white-space: nowrap; overflow-wrap: normal; text-align: right;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;模式系统&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="32" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;模式系统&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="120" y="120" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(159.5,131.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="64" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 65px; white-space: nowrap; overflow-wrap: normal; text-align: right;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;数据类型&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="32" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;数据类型&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="160" y="160" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(199.5,171.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="64" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 65px; white-space: nowrap; overflow-wrap: normal; text-align: right;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;起报时次&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="32" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;起报时次&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="200" y="200" width="120" height="40" fill="#fff2cc" stroke="#d6b656" pointer-events="none"/&gt;&lt;g transform="translate(239.5,211.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow:visible;" pointer-events="all" width="64" height="17" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 16px; font-family: &amp;quot;Lucida Console&amp;quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 65px; white-space: nowrap; overflow-wrap: normal; text-align: right;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;"&gt;数据文件&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="32" y="17" fill="#000000" text-anchor="middle" font-size="16px" font-family="Lucida Console"&gt;数据文件&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;</description></item><item><title>ecCodes学习笔记：使用conda在Windows中编译ecCodes</title><link>https://blog.perillaroc.wang/post/2019/2019-05-08-eccodes-notebook-build-in-anaconda-windows/</link><pubDate>Wed, 08 May 2019 20:32:22 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-08-eccodes-notebook-build-in-anaconda-windows/</guid><description>&lt;p&gt;&lt;strong&gt;2019年11月：新版本的eccodes已可以在Windows下解码JPEG压缩的GRIB2文件，所以请直接使用conda安装eccodes包。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ecmwf已与今年2月份官方提供windows环境下的ecCodes库，详情参见《&lt;a href="https://www.ecmwf.int/en/newsletter/159/news/eccodes-and-magics-available-under-windows"&gt;ecCodes and Magics available under Windows&lt;/a&gt;》。但经过我的实际测试，截止到2019年5月，使用conda安装的ecCodes不支持JPEG压缩，无法读取GRIB2最常见的数据种类，即使用JPEG压缩的GRIB2文件。因此，还是需要从源码编译。&lt;/p&gt;
&lt;p&gt;ecCodes已内置AppVeyor上的windows编译，参考&lt;code&gt;.appveyor.yml&lt;/code&gt;文件，使用conda环境在Windows中编译ecCodes。&lt;/p&gt;
&lt;h2 id="准备编译环境"&gt;准备编译环境&lt;/h2&gt;
&lt;p&gt;准备Visual Studio编译环境，我使用Visual Studio 2019测试。&lt;/p&gt;
&lt;p&gt;安装conda环境，例如安装Anaconda 3发行包。注：因为我不编译ecCodes的Python接口，所以可以使用python 3.x。&lt;/p&gt;
&lt;p&gt;可以创建一个单独的env用来编译ecCodes，例如我创建&lt;code&gt;nuwe_pyeeccodes&lt;/code&gt;环境，并通过Anaconda启动一个终端。&lt;/p&gt;
&lt;p&gt;启动终端后还需要激活 Visual Studio 编译环境，例如激活Visual Studio 2019 x64编译器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="配置环境变量"&gt;配置环境变量&lt;/h2&gt;
&lt;p&gt;需要的环境变量如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSTALL_DIR&lt;/code&gt;：ecCodes安装的目标位置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECCODES_SRC&lt;/code&gt;: ecCodes源码目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECBUILD_SRC&lt;/code&gt;: ecbuild源码目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="准备软件"&gt;准备软件&lt;/h2&gt;
&lt;p&gt;下载eccodes源码，可以下载软件包解压到目标路径&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone --depth 1 https://github.com/ecmwf/eccodes.git %ECCODES_SRC%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下载ecbuild源码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone --depth 1 https://github.com/ecmwf/ecbuild.git %ECBUILD_SRC%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="安装依赖库"&gt;安装依赖库&lt;/h2&gt;
&lt;p&gt;安装linux工具&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;conda install -c msys2 m2-bash &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-findutils &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-coreutils &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-grep &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-sed &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-gawk &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-diffutils &lt;span style="color:#ae81ff"&gt;^
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt; &lt;/span&gt; m2-perl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装最新版的cmake&lt;/p&gt;</description></item><item><title>迁移百度空间到Hugo</title><link>https://blog.perillaroc.wang/post/2019/2019-05-04-migrate-html-blog-to-hugo/</link><pubDate>Sat, 04 May 2019 15:35:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-04-migrate-html-blog-to-hugo/</guid><description>&lt;p&gt;2012年开始，我的个人博客由百度空间迁移到SAE。因为百度空间当时还能访问，转向到Wordpress时，就没有迁移百度空间上的文章。随着百度空间在2015年，所有文章以HTML格式保存在百度云中。今年从Wordpress迁移到Hugo，正好可以将百度空间的文章也迁移到Hugo。&lt;/p&gt;
&lt;p&gt;任务实际上就是将HTML博客转成Hugo文章。需要处理两个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将HTML转成Markdown，使用&lt;code&gt;html2txt&lt;/code&gt;实现&lt;/li&gt;
&lt;li&gt;增加Front Matter，使用&lt;code&gt;python-frontmatter&lt;/code&gt;实现&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="html转成markdown"&gt;HTML转成Markdown&lt;/h2&gt;
&lt;p&gt;读取HTML文件，使用&lt;code&gt;html2text.html2text&lt;/code&gt;库转成Markdown字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; html2text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(Path(blog_page_path), encoding&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; page_html &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;read()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text &lt;span style="color:#f92672"&gt;=&lt;/span&gt; html2text&lt;span style="color:#f92672"&gt;.&lt;/span&gt;html2text(page_html)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="创建front-matter"&gt;创建Front Matter&lt;/h2&gt;
&lt;p&gt;从HTML博客文章中提取标题和发布日期，使用&lt;code&gt;frontmatter.Post&lt;/code&gt;创建Front Matter对象，并使用&lt;code&gt;frontmatter.dumps&lt;/code&gt;转成Front Matter字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_front_matter&lt;/span&gt;(&lt;span style="color:#f92672"&gt;**&lt;/span&gt;kwargs):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; header &lt;span style="color:#f92672"&gt;=&lt;/span&gt; frontmatter&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Post(content&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; key &lt;span style="color:#f92672"&gt;in&lt;/span&gt; kwargs:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; header[key] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; kwargs[key]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; frontmatter&lt;span style="color:#f92672"&gt;.&lt;/span&gt;dumps(header)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;header &lt;span style="color:#f92672"&gt;=&lt;/span&gt; get_front_matter(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title&lt;span style="color:#f92672"&gt;=&lt;/span&gt;title,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date&lt;span style="color:#f92672"&gt;=&lt;/span&gt;release_time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strftime(&lt;span style="color:#e6db74"&gt;&amp;#39;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;T%H:%M:%S%z&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="组成hugo文章"&gt;组成Hugo文章&lt;/h2&gt;
&lt;p&gt;将Front Matter和Markdown字符串输出成文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;write_post&lt;/span&gt;(path, header, content):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(path, &lt;span style="color:#e6db74"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;, encoding&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(header)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(content)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完整示例请参考&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/perillaroc/2e3e21e79249da0f81a88420c9519730"&gt;perillaroc/convert_baidu_blog_to_hugo.py&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Matplotlib学习笔记：绘制风羽图</title><link>https://blog.perillaroc.wang/post/2019/2019-05-01-matplotlib-notebook-draw-brabs/</link><pubDate>Wed, 01 May 2019 20:53:10 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-01-matplotlib-notebook-draw-brabs/</guid><description>&lt;p&gt;气象上常见的矢量图有三种表现形式：箭头图、流线图、风羽图。
本文主要介绍风羽图的绘制。&lt;/p&gt;
&lt;p&gt;与箭头图一样，流线图需要准备两个分量的数据，并绘制地图。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;请参考箭头图的数据说明，下面绘制 850HPa 的风场图。&lt;/p&gt;
&lt;h2 id="绘制箭头图"&gt;绘制箭头图&lt;/h2&gt;
&lt;p&gt;Matplotlib 提供 &lt;code&gt;barbs&lt;/code&gt; 绘制流线图图。
使用 cartopy 为数据添加投影，并绘制地图。&lt;/p&gt;
&lt;p&gt;直接使用原始数据绘图风羽太密，需要对数据进行采样。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; cartopy.crs &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ccrs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;f &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;figure(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_subplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;111&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; projection&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccrs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PlateCarree(central_longitude&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vector_crs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ccrs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PlateCarree()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x &lt;span style="color:#f92672"&gt;=&lt;/span&gt; u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lons[::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;y &lt;span style="color:#f92672"&gt;=&lt;/span&gt; u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lats[::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;U &lt;span style="color:#f92672"&gt;=&lt;/span&gt; u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_values[::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;V &lt;span style="color:#f92672"&gt;=&lt;/span&gt; v_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_values[::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;S &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sqrt(U &lt;span style="color:#f92672"&gt;*&lt;/span&gt; U &lt;span style="color:#f92672"&gt;+&lt;/span&gt; V &lt;span style="color:#f92672"&gt;*&lt;/span&gt; V)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;max(S), np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;min(S))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ax&lt;span style="color:#f92672"&gt;.&lt;/span&gt;barbs(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; x, y, U, V, S,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transform&lt;span style="color:#f92672"&gt;=&lt;/span&gt;vector_crs,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; barb_increments&lt;span style="color:#f92672"&gt;=&lt;/span&gt;dict(half&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, full&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, flag&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ax&lt;span style="color:#f92672"&gt;.&lt;/span&gt;coastlines()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;show()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果如下图所示。&lt;/p&gt;</description></item><item><title>Matplotlib学习笔记：绘制流线图</title><link>https://blog.perillaroc.wang/post/2019/2019-05-01-matplotlib-notebook-draw-streamline/</link><pubDate>Wed, 01 May 2019 20:53:02 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-01-matplotlib-notebook-draw-streamline/</guid><description>&lt;p&gt;气象上常见的矢量图有三种表现形式：箭头图、流线图、风羽图。本文主要介绍流线图的绘制。&lt;/p&gt;
&lt;p&gt;与箭头图一样，流线图需要准备两个分量的数据，并绘制地图。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;请参考箭头图的数据说明，下面绘制850HPa的风场图。&lt;/p&gt;
&lt;h2 id="绘制箭头图"&gt;绘制箭头图&lt;/h2&gt;
&lt;p&gt;Matplotlib提供&lt;code&gt;streamplot&lt;/code&gt;绘制流线图图。使用cartopy为数据添加投影，并绘制地图。&lt;/p&gt;
&lt;p&gt;直接使用原始数据绘图速度太慢，最好对数据进行采样。默认设置流线太稀疏，设置&lt;code&gt;density&lt;/code&gt;提高流线的密度。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; plt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; cartopy.crs &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; ccrs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;f &lt;span style="color:#f92672"&gt;=&lt;/span&gt; plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;figure(figsize&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ax &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_subplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;111&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; projection&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccrs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PlateCarree(central_longitude&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vector_crs &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ccrs&lt;span style="color:#f92672"&gt;.&lt;/span&gt;PlateCarree()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ax&lt;span style="color:#f92672"&gt;.&lt;/span&gt;streamplot(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lons[::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;], u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lats[::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_values[::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;], v_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_values[::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; transform&lt;span style="color:#f92672"&gt;=&lt;/span&gt;vector_crs,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; density&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color&lt;span style="color:#f92672"&gt;=&lt;/span&gt;u_data&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_values[::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;, ::&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmap&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;autumn&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ax&lt;span style="color:#f92672"&gt;.&lt;/span&gt;coastlines()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plt&lt;span style="color:#f92672"&gt;.&lt;/span&gt;show()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2019/matplotlib/streamline.png" alt=""&gt;&lt;/p&gt;</description></item><item><title>Matplotlib学习笔记：绘制矢量箭头图</title><link>https://blog.perillaroc.wang/post/2019/2019-05-01-matplotlib-notebook-draw-vector/</link><pubDate>Wed, 01 May 2019 18:30:16 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-05-01-matplotlib-notebook-draw-vector/</guid><description>&lt;p&gt;气象上常见的矢量图有三种表现形式：箭头图、流线图、风羽图。
本文主要介绍矢量箭头图的绘制。&lt;/p&gt;
&lt;p&gt;与填充图略微不同的是，矢量图需要准备两个分量的数据。
其余部分与填充图相同，都需要绘制底图。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;以读取 GRIB2 数据为例说明如何准备数据，与绘制填充图博文一样，使用 &lt;a href="https://github.com/perillaroc/nuwe-pyeccodes"&gt;nuwe_pyeccodes&lt;/a&gt; 库读取 GRIB2 数据。&lt;/p&gt;
&lt;p&gt;使用 GRAPES GFS 的 GRIB2 数据，序号 131 和 171 的场代表 850HPa 的 u、v 分量。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; nuwe_pyeccodes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# get message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nuwe_pyeccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;GribFileHandler()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;openFile(&lt;span style="color:#e6db74"&gt;&amp;#34;F:/data/gfs/gmf.gra.2019042500000.grb2&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# gh 850HPa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;131&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; u_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;next()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;131&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;171&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;next()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建一个类 &lt;code&gt;GridData&lt;/code&gt; 方便将 GRIB 消息转成 numpy 矩阵。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; numpy &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; np
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GridData&lt;/span&gt;(object):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, grib_message):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; left_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; right_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lon_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;iDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getLong(&lt;span style="color:#e6db74"&gt;&amp;#39;Ni&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lon_array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(left_lon, right_lon &lt;span style="color:#f92672"&gt;+&lt;/span&gt; lon_step &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, lon_step)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; top_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bottom_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lat_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;jDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ny &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getLong(&lt;span style="color:#e6db74"&gt;&amp;#39;Nj&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lat_array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(top_lat, bottom_lat &lt;span style="color:#f92672"&gt;-&lt;/span&gt; lat_step &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;lat_step)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lons, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lats &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;meshgrid(lon_array, lat_array)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDoubleArray(&lt;span style="color:#e6db74"&gt;&amp;#39;values&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;grid_values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; values&lt;span style="color:#f92672"&gt;.&lt;/span&gt;reshape(ny, nx)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;GribData&lt;/code&gt;生成Matplotlib需要的数据。&lt;/p&gt;</description></item><item><title>再见AIX</title><link>https://blog.perillaroc.wang/post/2019/2019-04-30-farewell-aix/</link><pubDate>Tue, 30 Apr 2019 12:35:49 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-30-farewell-aix/</guid><description>&lt;p&gt;从入职的 2013 年到 2018 年，单位的数值预报业务系统全部运行在 IBM 的 AIX 高性能计算机上。
2018 年 CMA 采购 &lt;strong&gt;曙光-PI&lt;/strong&gt; 高性能计算机 (CMA-PI)，作为第一批启动业务迁移的单位，经过近一年的时间，我们已将主要的业务系统迁移到PI上，剩余的业务系统今年将全部迁移到新的HPC上。
随着 IBM 上的个人账户将于月底封停，是时候向 AIX 操作系统说再见了。&lt;/p&gt;
&lt;h2 id="aix"&gt;AIX&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;用一句话总结上一代的 IBM HPC：对于运维很不友好。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;虽然 AIX 是基于 UNIX 的操作系统，但 NMIC 在 AIX 上并没有安装足够的开发环境。
例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gcc&lt;/code&gt; 只是 &lt;code&gt;xlc&lt;/code&gt; 的别名，无法使用 &lt;code&gt;gcc&lt;/code&gt; 编译软件&lt;/li&gt;
&lt;li&gt;缺乏一整套编译工具，包括 &lt;code&gt;autotools&lt;/code&gt;、&lt;code&gt;cmake&lt;/code&gt;等&lt;/li&gt;
&lt;li&gt;Python 只是 2.6 版本，缺少增加大量特性的 2.7 或 3.X&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，业务系统运维工具的开发变得尤为困难，必须得构建一整套开发环境才能顺利实现工具开发。&lt;/p&gt;
&lt;p&gt;当然，上面的问题都属于应用问题，通过自己编译软件还是能解决。
最严重的问题还是在系统架构和系统软件的方面。&lt;/p&gt;
&lt;p&gt;据“不负责任”消息来源说，CMA 订购的这套高性能计算机系统不是针对高性能计算而是针对于分布式计算的。
不管事实与否，表现形式就是提交的作业经常不明原因出错，给出的故障往往是 InfiniBand 网卡问题。
另一个严重的问题就是提交 LoadLeveler 作业失败，为了解决这个问题，我修改了业务系统作业提交脚本，使用随机延迟避免同一时刻大量提交作业，检测作业失败并自动重新提交。
这个问题从我们迁移业务的第一年就开始出现，直到 2019 年的今天依然没有解决。
这令我止不住怀疑，到底是能力的问题还是责任心的问题。&lt;/p&gt;
&lt;p&gt;进入农历猪年，不知道是不是因为 CMA 未来不会再购买 IBM 的 HPC，uranus 的运行环境急剧恶化，节点多次关停重启，队列作业异常问题也缺乏足够的反馈。
即便对 AIX 有一丝怀念，可扛不住半夜起来处理现实的现实。
因此，汛期前一定要将所有主要的业务系统迁移到 CMA-PI 上。&lt;/p&gt;</description></item><item><title>Hugo集成reveal.js幻灯片</title><link>https://blog.perillaroc.wang/post/2019/2019-04-28-use-revealjs-in-hugo/</link><pubDate>Sun, 28 Apr 2019 19:42:38 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-28-use-revealjs-in-hugo/</guid><description>&lt;p&gt;博客中嵌入幻灯片是一种不错的内容展现形式，本文介绍Hugo中集成reveal.js幻灯片的两种方式，同样也适用于其他幻灯片库。&lt;/p&gt;
&lt;h2 id="总体思路"&gt;总体思路&lt;/h2&gt;
&lt;p&gt;HTML版幻灯片是一个单独的网页，可以在页面中使用&lt;code&gt;iframe&lt;/code&gt;加载网页。&lt;/p&gt;
&lt;p&gt;如果幻灯片库支持内嵌，也可以不使用&lt;code&gt;iframe&lt;/code&gt;，直接在文章中插入幻灯片内容。很遗憾，reveal.js的内嵌功能有问题，与内嵌相关的issue至今仍没有close。&lt;/p&gt;
&lt;h2 id="集成在线幻灯片"&gt;集成在线幻灯片&lt;/h2&gt;
&lt;p&gt;如果幻灯片可以在线访问，就可以直接集成到文章中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;iframe&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;//slides.com/rocperilla/esmdiag/embed?style=dark&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;width&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;576&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;height&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;420&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;scrolling&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;no&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;frameborder&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;webkitallowfullscreen&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mozallowfullscreen&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;allowfullscreen&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;iframe&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;效果如下面所示，注意slides.com可能需要科学上网。&lt;/p&gt;
&lt;iframe src="//slides.com/rocperilla/esmdiag/embed?style=dark"
 width="576" height="420" scrolling="no" frameborder="0" 
 webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;
&lt;/iframe&gt;
&lt;h2 id="生成幻灯片"&gt;生成幻灯片&lt;/h2&gt;
&lt;p&gt;如果不想使用在线服务，或者无法使用在线服务，也可以使用Hugo生成reveal.js网页。&lt;/p&gt;
&lt;p&gt;我们需要为幻灯片单独指定一个content类型，并创建相关的模板文件。&lt;/p&gt;
&lt;p&gt;Hugo的内容模板保存在&lt;code&gt;layouts&lt;/code&gt;文件夹中，主题默认类型的内容模板保存在主题目录的&lt;code&gt;_default&lt;/code&gt;文件夹，想要创建一种新类型的内容模板，需要在&lt;code&gt;layouts&lt;/code&gt;下新建一个目录，例如创建&lt;code&gt;slide&lt;/code&gt;目录，表示幻灯片类型，并在该目录下创建模板文件。&lt;/p&gt;
&lt;p&gt;需要两种模板：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;baseof.html&lt;/code&gt;：基本框架&lt;/li&gt;
&lt;li&gt;&lt;code&gt;single.html&lt;/code&gt;：单页内容模板&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;baseof.html&lt;/code&gt;中可以引用reveal.js的css和js文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.8.0/css/reveal.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.8.0/css/theme/moon.css&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;body&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{{ block &amp;#34;main&amp;#34; . }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{{ with .Content }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		{{ . }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.8.0/js/reveal.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;DOMContentLoaded&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Reveal&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;initialize&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;single.html&lt;/code&gt;中显示实际的幻灯片&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{{ define &amp;#34;main&amp;#34; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;reveal&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{{ .Content }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{{ end }}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;content&lt;/code&gt;中新建一个目录，例如&lt;code&gt;slide&lt;/code&gt;，保存幻灯片类型的文档。创建文档时，需要在 front matter 中显式指定type和layout。&lt;/p&gt;</description></item><item><title>NWPC业务系统笔记：构建数值预报业务系统</title><link>https://blog.perillaroc.wang/post/2019/2019-04-27-nwpc-system-notebook-build-operation-system/</link><pubDate>Sat, 27 Apr 2019 07:11:51 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-27-nwpc-system-notebook-build-operation-system/</guid><description>&lt;p&gt;三年多前开始研究 SMS 的升级版 ecFlow，翻译了 ecFlow 的官方教程。
我还尝试使用 ecFlow 的 python api 接口创建 SMS 的 def 文件，应用在业务系统中。
但因为与其他业务系统的构建方式不一致，给维护带来不小的麻烦。&lt;/p&gt;
&lt;p&gt;去年单位的 HPC 由 IBM AIX 切换为曙光 Linux，作业调度软件也由 SMS 升级成 ecFlow，我也正式开始使用 ecFlow 构建数值预报业务系统。&lt;/p&gt;
&lt;h2 id="sms与ecflow的区别"&gt;SMS与ecFlow的区别&lt;/h2&gt;
&lt;p&gt;ecFlow 是 SMS 的升级版，继承 SMS 的基本概念，业务系统可以延续 SMS 的构建方式。
但需要对系统进行一定的修改，详细的迁移方案请参考ecFlow官方网站
&lt;a href="https://confluence.ecmwf.int/display/ECFLOW/Migration+from+SMS+to+ecFlow"&gt;Migration from SMS to ecFlow&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="api"&gt;API&lt;/h3&gt;
&lt;p&gt;对于用户来说，ecFlow 相对于 SMS 最大的变化就是提供了 Python API 接口，用于构建系统流程和实现与服务器的交互。&lt;/p&gt;
&lt;p&gt;ecFlow 和 SMS 使用相同语法的 def 文件来定义系统流程，详细语法规则请参考 &lt;a href="https://confluence.ecmwf.int/display/ECFLOW/Definition+file+Grammar"&gt;Definition file Grammar&lt;/a&gt;。
直接编写 def 文件可以定义系统，但 def 语法不提供定义复杂系统需要的循环、判断等编程语言的基本要素。
因此两者都内置工具生成 def 文件。&lt;/p&gt;
&lt;p&gt;SMS 提供自定义的 CDP 接口创建 def 文件，语法规则类似 shell，因此也保留了 shell 中循环、判断语法规则不灵活的特点。&lt;/p&gt;</description></item><item><title>HPC用户安装Python解决方案</title><link>https://blog.perillaroc.wang/post/2019/2019-04-22-user-level-python-for-hpc/</link><pubDate>Mon, 22 Apr 2019 21:11:34 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-22-user-level-python-for-hpc/</guid><description>&lt;p&gt;单位今年全新投入业务运行的高性能计算机 CMA-PI 中已安装多个版本的 Python 环境，包括 Python 2.7 / 3.6，anaconda 2/3。
但为了方便安装第三方 Python 库，还是需要在用户目录下安装 Python 环境。&lt;/p&gt;
&lt;p&gt;下面介绍自建 Python 的解决方案。&lt;/p&gt;
&lt;h2 id="python-发行包"&gt;Python 发行包&lt;/h2&gt;
&lt;h3 id="编译-python-源码"&gt;编译 Python 源码&lt;/h3&gt;
&lt;p&gt;CMA-PI 的操作系统是 RedHat，编译软件比原来的 IBM AIX 更方便，可以直接编译 Python 源码。
Python 源码编译基本采用默认配置即可。&lt;/p&gt;
&lt;p&gt;PI 上编译 Python 3.7 的 &lt;code&gt;configure&lt;/code&gt; 命令如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$WORKDIR/usr/local/bin --enable-optimizations CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;g++
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;prefix&lt;/code&gt; 指定 Python 安装的位置。
可以模拟系统的 &lt;code&gt;/usr/local&lt;/code&gt; 目录，在工作目录中创建相同的目录结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;WORKDIR&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;/usr/local/bin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PI 上已安装多种编译器，这里直接指定使用 &lt;code&gt;g++&lt;/code&gt; 编译。&lt;/p&gt;
&lt;p&gt;安装后将 &lt;code&gt;$WORKDIR/usr/local/bin&lt;/code&gt; 加入环境变量 &lt;code&gt;PATH&lt;/code&gt;，即可使用编译的 Python 环境。&lt;/p&gt;
&lt;h3 id="安装-anaconda"&gt;安装 Anaconda&lt;/h3&gt;
&lt;p&gt;Anaconda 支持非管理员账户安装，下载 Linux 安装包，在 CMA-PI 上运行，指定用户目录即可安装。&lt;/p&gt;</description></item><item><title>突破防火墙封锁：使用CCProxy访问互联网</title><link>https://blog.perillaroc.wang/post/2019/2019-04-19-use-ccproxy-to-access-internet/</link><pubDate>Fri, 19 Apr 2019 21:10:12 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-19-use-ccproxy-to-access-internet/</guid><description>&lt;p&gt;单位的高性能计算机去年由 IBM 切换到曙光，操作系统也由 AIX 换成 Linux，使用开发工具变得更加方便，因此进行一系列工具软件的开发。
不论之前大量使用的 Python，还是今年开始学习的 Go，配置开发环境都需要安装大量的软件包。
单位的 HPC 均无法连接外网，离线安装依赖包非常费劲，所以 HPC 上还是需要能在线更新的开发环境。
这就需要使用代理。&lt;/p&gt;
&lt;p&gt;之前的一篇博文介绍使用 squid 架设代理，需要修改文本格式的配置文件，不容易使用，参见《&lt;a href="https://blog.perillaroc.wang/post/2013/2013-10-13-use-squid-to-access-internet/"&gt;突破防火墙封锁：使用Squid代理上网&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;CCProxy 是面向 Windows 平台的代理工具，提供图形界面，配置代理十分方便。
本文介绍如何使用 CCProxy 让 HPC 的个人账户可以访问互联网。&lt;/p&gt;
&lt;h2 id="安装ccproxy"&gt;安装CCProxy&lt;/h2&gt;
&lt;p&gt;从官方网站上下载 CCProxy 并安装，对于个人账户，我们只需要设置一个用户，使用免费的试用版即可。&lt;/p&gt;
&lt;p&gt;下载地址：&lt;a href="//www.ccproxy.com/download.htm"&gt;www.ccproxy.com/download.htm&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="开始使用"&gt;开始使用&lt;/h2&gt;
&lt;p&gt;启动软件，如下图所示&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2019/ccproxy-main.png" alt="CCProxy主界面"&gt;&lt;/p&gt;
&lt;p&gt;打开设置菜单，可以看到软件使用的默认端口号为 808，并已经打开了部分协议的代理&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2019/ccproxy-setting.png" alt="CCProxy设置"&gt;&lt;/p&gt;
&lt;p&gt;HPC 上配置 &lt;code&gt;http_proxy&lt;/code&gt; 和 &lt;code&gt;https_proxy&lt;/code&gt; 即可使用 CCProxy 通过代理上网。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export http_proxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://192.168.1.2:808
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export https_proxy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;http://192.168.1.2:808
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="配置账户权限"&gt;配置账户权限&lt;/h2&gt;
&lt;p&gt;CCProxy 也支持定义账户权限，点击账号按钮，默认允许所有账号连接代理服务&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2019/ccproxy-account.png" alt="CCProxy账号管理"&gt;&lt;/p&gt;
&lt;p&gt;可以修改为“允许部分”，并添加账户&lt;/p&gt;
&lt;p&gt;&lt;img src="//cdn.perillaroc.wang/image/blog/2019/ccproxy-add-account.png" alt="CCProxy添加账户"&gt;&lt;/p&gt;</description></item><item><title>使用LeanCloud替换MongoDB</title><link>https://blog.perillaroc.wang/post/2019/2019-04-12-replace-mongodb-with-leancloud/</link><pubDate>Fri, 12 Apr 2019 21:37:00 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-12-replace-mongodb-with-leancloud/</guid><description>&lt;p&gt;在 Wordpress 迁移到 Hugo 中寻找评论解决方案时，发现 &lt;a href="//valine.js.org"&gt;valine&lt;/a&gt; 使用的云存储平台 &lt;a href="//leancloud.cn"&gt;LeanCloud&lt;/a&gt; 提供的数据模型与 MongoDB 类似，并且提供的免费资源（日操作低于30000次）足够个人博客等小型网站使用。&lt;/p&gt;
&lt;p&gt;单位业务监控的外网服务器 &lt;a href="//github.com/nwpc-oper/nmp-web"&gt;nmp-web&lt;/a&gt; 搭建在我自己购买的阿里云服务器上，使用 MongoDB 和 Redis 存储数据。因为 MongoDB占用的资源较多，云服务器只有1G内存，MongoDB 经常因查询而崩溃。保存到 MongoDB 中的数据访问量很少，LeanCloud 的开发版完全可以满足需求。所以，已经使用 LeanCloud 替换 MongoDB，降低云服务器的负载，同时也是对 Serverless 的一种尝试。&lt;/p&gt;
&lt;h2 id="数据模型"&gt;数据模型&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;LeanCloud 的存储后台大量采用了 MongoDB 这种文档数据库来存储结构化数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MongoDB 的数据结构可以直接保存到 LeanCloud 中，与 MongoDB 不同的是，LeanCloud 的一个 Class 中的数据必须有相同的格式。&lt;/p&gt;
&lt;p&gt;nmp-web 接收的 json 数据是来自 &lt;code&gt;pymongo&lt;/code&gt; 的 BSON 转成的字典对象，具有相同的结构，可以保存到 LeanCloud 的一个 Class 中。&lt;/p&gt;
&lt;h2 id="存储"&gt;存储&lt;/h2&gt;
&lt;p&gt;为了检索方便，将其中的 &lt;code&gt;timestamp&lt;/code&gt; 数据重新解析成 LeanCloud 可以识别的 &lt;code&gt;datetime&lt;/code&gt; 格式。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;save_blob&lt;/span&gt;(blob: dict) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Blob()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; blob[&lt;span style="color:#e6db74"&gt;&amp;#39;timestamp&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strptime(blob[&lt;span style="color:#e6db74"&gt;&amp;#39;timestamp&amp;#39;&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;T%H:%M:%S&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b&lt;span style="color:#f92672"&gt;.&lt;/span&gt;set(blob)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b&lt;span style="color:#f92672"&gt;.&lt;/span&gt;save()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="检索"&gt;检索&lt;/h2&gt;
&lt;p&gt;检索也非常方便，例如按照 &lt;code&gt;ticket_id&lt;/code&gt; 检索某个数据。&lt;/p&gt;</description></item><item><title>提取Git项目中的子目录为新的项目</title><link>https://blog.perillaroc.wang/post/2019/2019-04-11-split-a-subflolder-into-a-new-repository-in-git/</link><pubDate>Thu, 11 Apr 2019 15:46:47 +0800</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-04-11-split-a-subflolder-into-a-new-repository-in-git/</guid><description>&lt;p&gt;一个完成复杂任务的项目可能会由多个组件协作完成。例如单位使用的&lt;a href="https://github.com/perillaroc/nwpc-monitor-platform"&gt;nwpc-monitor-platform&lt;/a&gt;项目，就由下面几个组件构成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nmp-model: 模型&lt;/li&gt;
&lt;li&gt;nmp-broker: 内网服务器&lt;/li&gt;
&lt;li&gt;nmp-scheduler: 定时调度器&lt;/li&gt;
&lt;li&gt;nmp-web: 外网服务器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当项目越来越庞大时，使用一个单一的项目管理各个组件开始变得比较臃肿，为了方便各个组件的后续开发，最好将它们拆开，保存为不同的项目。这就涉及到如何提取Git中的某个子目录为一个新的项目。&lt;/p&gt;
&lt;h2 id="提取子目录"&gt;提取子目录&lt;/h2&gt;
&lt;p&gt;Github给出了详细的说明，参见《&lt;a href="https://help.github.com/en/articles/splitting-a-subfolder-out-into-a-new-repository"&gt;Splitting a subfolder out into a new repository&lt;/a&gt;》。&lt;/p&gt;
&lt;p&gt;下面简要说明各个步骤。&lt;/p&gt;
&lt;p&gt;首先在一个新的目录中克隆整个项目。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/perillaroc/nwpc-monitor-platform.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着在克隆的目录中提取子目录，例如提取nmp-broker到master分支&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git filter-branch --prune-empty --subdirectory-filter nmp-broker master
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后修改remote origin的url地址，指向新项目。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git remote set-url origin https://github.com/nwpc-oper/nmp-broker.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，更新远程项目。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push -u origin master
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="子模块"&gt;子模块&lt;/h2&gt;
&lt;p&gt;如果拆分子目录后想要保留原有项目的目录结构不变，可以使用子模块（submodule）将拆分后的项目与原项目关联。
这样原有的部署方案依然有效。但submodule据说有各式各样的坑，所以还是要改掉原有的部署方案，适应项目的变化。&lt;/p&gt;
&lt;p&gt;添加子模块的命令如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git submodule add https://github.com/nwpc-oper/nmp-broker.git nmp-borker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用git-filter-repo"&gt;使用git-filter-repo&lt;/h2&gt;
&lt;p&gt;2020.01 更新&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;git filter-branch&lt;/code&gt; 会提示使用git-filter-repo工具。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/newren/git-filter-repo"&gt;https://github.com/newren/git-filter-repo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;该工具CLI接口类似，但效率更高。参看如下示例：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;(base) D:\ploto&amp;gt;python ..\git-filter-repo.py --subdirectory-filter ploto-gidat
Parsed 182 commits
New history written in 0.87 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
HEAD is now at c387ac5 :building_construction: move gidat into ploto_gidat module. fix #6
Enumerating objects: 40, done.
Counting objects: 100% (40/40), done.
Delta compression using up to 12 threads
Compressing objects: 100% (31/31), done.
Writing objects: 100% (40/40), done.
Total 40 (delta 4), reused 27 (delta 0)
Completely finished after 1.71 seconds.
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>从Gitbooks迁移到Hugo</title><link>https://blog.perillaroc.wang/post/2019/2019-03-31-migrate-from-gitbooks-to-hugo/</link><pubDate>Sun, 31 Mar 2019 20:44:32 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-03-31-migrate-from-gitbooks-to-hugo/</guid><description>&lt;p&gt;新版gitbooks已开始全面收费，cli工具也不再继续更新，gitbooks已不适合部署开源项目的文档。虽然旧版的gitbook工具可以满足绝大部分的需求，但为了后续开发，需要选择一款新的文档生成器。&lt;br&gt;
Hugo是一款使用Go开发的静态网站生成工具，结合社区开发的丰富主题，可以很方便地开发文档网站。因为Hugo与gitbook一样使用Markdown编写内容，所以从Gitbooks迁移到Hugo十分简单。&lt;/p&gt;
&lt;h2 id="目录结构"&gt;目录结构&lt;/h2&gt;
&lt;p&gt;gitbook使用一个单一的文件SUMMARY.md表示目录结构，与内容文件的目录结构无关。在Hugo中网站的目录结构与内容的目录一致。&lt;br&gt;
如果gitbook中文件目录结构与文档目录结构一致，迁移时无需修改目录结构，只需要将父目录对应的文件名修改为_index.md即可。&lt;/p&gt;
&lt;h2 id="文件内容"&gt;文件内容&lt;/h2&gt;
&lt;p&gt;将每个文件的标题改成Hugo的文件头Front Matter，并加入weight参数，填入该页面在目录中的序号。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;文件标题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;weight&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="主题"&gt;主题&lt;/h2&gt;
&lt;p&gt;强烈推荐&lt;a href="https://github.com/matcornic/hugo-theme-learn"&gt;hugo-theme-learn&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="部署"&gt;部署&lt;/h2&gt;
&lt;p&gt;参考Hugo文档《&lt;a href="https://gohugo.io/hosting-and-deployment/hosting-on-github/#github-project-pages"&gt;Host on GitHub&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;请访问《&lt;a href="https://perillaroc.github.io/eccodes-tutorial-cn/"&gt;ecCodes GRIB教程中文版&lt;/a&gt;》&lt;br&gt;
文档源代码：&lt;a href="https://github.com/perillaroc/eccodes-tutorial-cn"&gt;perillaroc/eccodes-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="图片"&gt;图片&lt;/h2&gt;
&lt;p&gt;如果章节中含有图片，则需要额外的处理。&lt;br&gt;
&lt;img src="http://wx1.sinaimg.cn/large/4afdac38ly1g1ndrddax5j20fh0imabh.jpg" width="557" height="670" class="alignnone" /&gt;&lt;br&gt;
在上面的图片中，原有gitbook的图片都保存在 02-grib-tools 的 asset 文件夹下。但将其转为 Hugo 后，只有 _index.md，即 02-grib-tools 的目录章节，与原有的 asset 在同一个路径下/02-grib-tools/，其余子页面均在子路径下，例如&lt;code&gt;/02-grib-tools/copy\_messages/&lt;/code&gt;。所以文档中的 asset 目录指/02-grib-tools/copy_messages/asset，不是/02-grib-tools/asset。&lt;br&gt;
如果不想修改文档中的图片链接，可以将文档章节放到一个单独的文件夹中，Hugo 将其称为 Page Bundle。将文档移动到该目录下，并改名为 _index.md，同时将需要的图片放到该目录下的asset目录中。类似上面图中的 grib_keys 目录。这样，就可以编译后的网站就正常访问图片了。&lt;/p&gt;</description></item><item><title>2018年个人总结</title><link>https://blog.perillaroc.wang/post/2019/2019-03-25-2018-summary/</link><pubDate>Mon, 25 Mar 2019 12:09:59 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-03-25-2018-summary/</guid><description>&lt;p&gt;女儿的出生，生活从此变得和之前不一样。
拖到三月底还没有写成，去年的个人总结又一次可能泡汤了。
明天休完探亲假去上班，今天把之前写的整理下，做个简单的总结吧。&lt;/p&gt;
&lt;h2 id="微风女神aura"&gt;微风女神Aura&lt;/h2&gt;
&lt;p&gt;家里迎来一个新的生命，愿女儿健康快乐地成长。&lt;/p&gt;
&lt;h2 id="山水甲天下"&gt;山水甲天下&lt;/h2&gt;
&lt;p&gt;上半年去了日本，下半年去了桂林，都是风景秀美的地方。&lt;/p&gt;
&lt;h2 id="第六年"&gt;第六年&lt;/h2&gt;
&lt;h3 id="移植"&gt;移植&lt;/h3&gt;
&lt;p&gt;去年被系统移植和升级工作牵涉大量精力，自从同事离职后，原本其它部门负责的业务系统重新交给我们部门，而我事实上负责业务后处理系统的维护工作。
虽然同事在离职前已经完成大部分移植工作，后续的切换和升级还是让我深刻感受到系统建设和维护工作的困境。&lt;/p&gt;
&lt;p&gt;系统建设实际上是个体力活，但想要方便地完成系统维护和升级，在构建系统时需要考虑多种因素。
移植的产品后处理系统就是个很典型的例子：系统中包含大量没有实际调用的脚本，这点其实和我们缺乏对运行脚本的版本管理有关系；大量紧耦合的任务放在同一个脚本中，某次更新就因为没有详细检查而导致数据出错。
为了系统的持续发展，需要对整个系统的流程和脚本进行重构。
问题就在这里，谁来干？&lt;/p&gt;
&lt;p&gt;系统建设这种通常被认为缺乏创新点的工作需要花费大量时间，却很难成为为晋升增分的业绩。
在强调科研工作的单位里，投入-产出比太低，没有任何动力去做，除非有其他原因必须做这件事。
记得某次开会领导专门提到科研人员的时间更应该花在科学研究上，而不应该花在建业务系统这类事情上。
这就是我们部门后续发展所面临的最大问题，我们负责所有业务系统的建立和运维，随着业务运行的系统没有限制的增长，这部分工作会占用越来越多的时间和精力，留给能带来有效业绩工作的时间会越来越少。
去年阅读的一本书中给了我一定的启发，可以尝试宣传谁开发谁负责的观点，运维部门负责提供系统运行的工具，而不负责具体业务系统的建设。
虽然不会被接受，但就怕有万一，万一成了呢？&lt;/p&gt;
&lt;h3 id="运维"&gt;运维&lt;/h3&gt;
&lt;p&gt;去年工作中变化最大的一个方面就是业务系统运维面临更大的压力。
随着气象局大力推广GRAPES模式应用，我们的产品从无人问津变得用户逐渐增多，我们也面临着从保障系统稳定运行到保障产品按时分发的目标转换。
但无论是我们部门还是整个单位，都没有对运维目标的转换有足够的重视，仅仅认为保障业务运行是我们一个部门的职责，在工作计划中也没有投入足够的人力去研究如何更好地运维。
在系统迁移和用户增多的双重压力下，业务系统发生一次严重的事故，直接导致领导对我们整个部门的不信任，以及随之而来的一系列风波。
中间经历一系列的交锋，让我认识了自己，也认清了很多事情。
最终的结果是值班时长从1人1周改为1人3天，同时不再让其他部门单独值班。
不过，这仅仅是一个部门与领导双方妥协的临时方案，仅仅改变值班频次无法提高系统维护的水平，今年我们依然面临来自领导和系统本身的运维压力。&lt;/p&gt;
&lt;p&gt;我一直认为单纯依靠人力无法提高运维水平，无论是强调工作态度，还是增加其他人手，对于受大量外界条件影响的数值预报业务系统来讲，都没有显著的效果。
经过多年的锻炼，我们的问题不在于解决故障的能力，而在于发现故障的速度。
影响产品分发的故障处理很多都是因为发现故障时间较晚，导致产品无法按时生成，因为模式积分耗时较长，而预报员对预报产品有时间要求，留给运维人员处理故障的只有有限的时间窗。&lt;/p&gt;
&lt;p&gt;领导认为，我们没能按时发现故障是因为我们的责任心不强，对工作不够认真负责，所以期望通过引入更严格的考核机制，来区分每个值班人员的值班效果。
我个人完全反对这种没有正效果的措施，且不说所谓值班效果很难界定，这种方案完全忽视了对具体问题的分析，也严重打击值班人员的工作积极性。
还好，这项提议被暂时搁置了。
我在今年汛期前还还有机会实施自己的方案，即通过技术手段提高运维能力。&lt;br&gt;
运维也需要开发工具，需要使用自动化工具来提高效率。
去年这部分工作没有被列入计划中，也就缺少动力去深入研究。
不过，随着各个工程项目逐渐实施，我们部门可以借助第三方公司来开发一些运维工具。
今年部门也明确将运维开发写入工作计划中，期望今年我们的运维水平能有显著的提升。&lt;/p&gt;
&lt;h3 id="业务支撑"&gt;业务支撑&lt;/h3&gt;
&lt;p&gt;连续两年，我提出的监控方面任务都被拿掉，但去年还是花了大量精力去完成监控平台从IBM到PI上的迁移，并对工具进行一定的升级。
升级的部分包括重新设计的模型类，使用docker部署整个平台等。
另外还为ecFlow和slurm开发了一些维护工具。
去年基于图数据库开发了产品分发管理系统。&lt;/p&gt;
&lt;p&gt;今年领导终于重视运维工具的开发，我们将借助工程项目的力量进一步开发业务支撑工具，争取形成一套完整的运行监控系统，而不是现在我开发的各种分散的工具。&lt;/p&gt;
&lt;h3 id="研发支撑"&gt;研发支撑&lt;/h3&gt;
&lt;p&gt;缺乏明确的项目支持，去年诊断软件的开发基本处于搁置状态。
一直没有形成可以试用的版本，也导致开发五年没有成果。
我个人还是不太愿意做这个项目，没有把全部精力用来开发诊断软件平台。
今年如果还继续这样，就没有后续了。&lt;/p&gt;
&lt;h3 id="项目管理"&gt;项目管理&lt;/h3&gt;
&lt;p&gt;后半年领导将海洋工程中的一个项目交给我来管理，这才发现项目管理不是一件容易的事情。
我更擅长独立完成任务，缺乏团队合作意识，所以项目管理一塌糊涂。
今年需要大力借助工程项目的力量完成工作任务，所以这方面我还得继续加强。&lt;/p&gt;
&lt;h3 id="技术开发"&gt;技术开发&lt;/h3&gt;
&lt;p&gt;去年研究了 GRIB2 数据处理和 Matplotlib 绘图等技术，不再详细描述。&lt;/p&gt;
&lt;h2 id="编程-v2018"&gt;编程 v2018&lt;/h2&gt;
&lt;p&gt;可以看到 4 月到 5 月以及 10 月份基本没有什么编程。&lt;/p&gt;</description></item><item><title>pyslurm：Slurm的python接口</title><link>https://blog.perillaroc.wang/post/2019/2019-01-17-pyslurm-a-python-api-for-slurm/</link><pubDate>Thu, 17 Jan 2019 14:32:26 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2019/2019-01-17-pyslurm-a-python-api-for-slurm/</guid><description>&lt;p&gt;2018 年版本的 slurm-client 使用 &lt;code&gt;squeue -o %all&lt;/code&gt; 获取 slurm 中的作业信息，基本可以获取所需要的信息，但无法获取作业的标准输出和标准错误输出文件路径。
squeue 的 &lt;code&gt;-O&lt;/code&gt; 选项可以显示更多的信息，但必须指定每个栏目的宽度，不适合业务环境中路径长度变化较多的情况。
今年尝试使用 slurm 的 python 接口 &lt;a href="https://github.com/PySlurm/pyslurm"&gt;pyslurm&lt;/a&gt; 解决这个问题。&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;pyslurm 需要 cython 包和 slurm 库，使用 pip 安装 cython，使用源码安装 pyslurm。
安装 pyslurm 时，可以指定 slurm 库的位置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python setup.py build &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --slurm-lib&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PATH_TO_SLURM_LIB &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --slurm-inc&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PATH_TO_SLURM_INC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用"&gt;使用&lt;/h2&gt;
&lt;p&gt;示例代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; pyslurm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;job_object &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pyslurm&lt;span style="color:#f92672"&gt;.&lt;/span&gt;job()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;job_dict &lt;span style="color:#f92672"&gt;=&lt;/span&gt; job_object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第二行返回一个 &lt;code&gt;pyslurm.Job&lt;/code&gt; 对象，可以使用 &lt;code&gt;get()&lt;/code&gt; 获取所有作业的信息，返回字典格式。
使用 &lt;code&gt;std_out&lt;/code&gt; 就可以获取标准输出文件路径。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/perillaroc/nwpc-nost/tree/master/slurm-client"&gt;slurm-client&lt;/a&gt;&lt;/p&gt;</description></item><item><title>使用多个队列处理Celery任务</title><link>https://blog.perillaroc.wang/post/2018/2018-12-18-use-multi-queues-to-run-celery-tasks/</link><pubDate>Tue, 18 Dec 2018 20:02:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-12-18-use-multi-queues-to-run-celery-tasks/</guid><description>&lt;p&gt;当 RabbitMQ 作为后端时，Celery 默认使用名为 celery 的队列处理所有任务。
去年 NMP 项目中也采用这样的方式。
但今年任务量翻倍后，一次 beat 批量任务执行的总时间已超过 beat 的间隔，批量执行顺序会发生混乱，之前的方式无法处理增多的任务。&lt;/p&gt;
&lt;p&gt;尝试使用多个 worker 处理任务，发现依然存在问题：group 的某个任务会莫名丢失。&lt;/p&gt;
&lt;p&gt;一篇博文《&lt;a href="https://www.jianshu.com/p/9e422d9f1ce2"&gt;使用Celery踩过的坑&lt;/a&gt;》中指出单个队列执行大量任务可能会出现问题，建议为不同类型的任务设置不同的队列，并使用不同的 worker 执行每个队列中的任务。&lt;/p&gt;
&lt;p&gt;我没有仔细研究任务丢失的原因，确定采纳博文中的建议，使用多个任务处理 Celery 任务。&lt;/p&gt;
&lt;h2 id="配置"&gt;配置&lt;/h2&gt;
&lt;p&gt;Celery 使用路由 (routing) 实现任务向不同队列的分发，默认会自动创建需要的队列，所以最简单的使用方法就是在配置中设置路由项目，类似：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;task_routes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;feed.tasks.*&amp;#39;&lt;/span&gt;, {&lt;span style="color:#e6db74"&gt;&amp;#39;queue&amp;#39;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;feeds&amp;#39;&lt;/span&gt;}),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e6db74"&gt;&amp;#39;web.tasks.*&amp;#39;&lt;/span&gt;, {&lt;span style="color:#e6db74"&gt;&amp;#39;queue&amp;#39;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;web&amp;#39;&lt;/span&gt;}),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (re&lt;span style="color:#f92672"&gt;.&lt;/span&gt;compile(&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;(video|image)\.tasks\..*&amp;#39;&lt;/span&gt;), {&lt;span style="color:#e6db74"&gt;&amp;#39;queue&amp;#39;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;media&amp;#39;&lt;/span&gt;}),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;],)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;未配置路由的任务会发送给默认队列，即 celery。
可以通过修改 &lt;code&gt;task_default_queue&lt;/code&gt; 配置项改变默认队列的名称。&lt;/p&gt;
&lt;h2 id="为-worker-设置队列"&gt;为 worker 设置队列&lt;/h2&gt;
&lt;p&gt;使用命令行启动 worker 可以通过 &lt;code&gt;-Q&lt;/code&gt; 设置多个队列，例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;celery -A proj worker -Q feeds,celery
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 API 接口启动 worker 则稍微复杂些，需要使用 &lt;code&gt;Celery.select_queues&lt;/code&gt; 函数，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;select_queues([&lt;span style="color:#e6db74"&gt;&amp;#39;feeds&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;celery&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Worker()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;start()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="应用效果"&gt;应用效果&lt;/h2&gt;
&lt;p&gt;使用不同的队列处理任务后，不再出现任务丢失的情况。&lt;/p&gt;</description></item><item><title>mongoengine文档转换为python字典</title><link>https://blog.perillaroc.wang/post/2018/2018-09-26-mongoengine-document-convert-to-python-dict/</link><pubDate>Wed, 26 Sep 2018 21:25:51 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-09-26-mongoengine-document-convert-to-python-dict/</guid><description>&lt;p&gt;mongoengine 使用 &lt;code&gt;Document&lt;/code&gt; 类表示 mongodb 中的文档，即一条记录。
如果想向外部系统发送该记录，例如向 web 服务器发送记录数据，就需要将 &lt;code&gt;Document&lt;/code&gt; 对象持久化。
Python 的字典是一种很容易持久化的类型，可以使用 json 序列化。
因此需要将 &lt;code&gt;Document&lt;/code&gt; 对象转为字典对象。&lt;/p&gt;
&lt;p&gt;mongoengine 没有提供从 &lt;code&gt;Document&lt;/code&gt; 直接转成 dict 的方法，但 mongoengine 底层由 pymongo 实现，所以 &lt;code&gt;Document&lt;/code&gt; 对象可以使用 &lt;code&gt;to_mongo&lt;/code&gt; 方法转成 pymongo 支持的对象 &lt;code&gt;bson.son.SON&lt;/code&gt;。
而 &lt;code&gt;SON&lt;/code&gt; 对象使用 &lt;code&gt;to_dict&lt;/code&gt; 方法可以得到 dict 对象。&lt;/p&gt;
&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;定义一个 &lt;code&gt;Document&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; mongoengine &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Document, StringField
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;(Document):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; email &lt;span style="color:#f92672"&gt;=&lt;/span&gt; StringField(required&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; first_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; StringField(max_length&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; last_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; StringField(max_length&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建对象&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; User(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; email&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;w@w.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; first_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Bob&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; last_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Doors&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将对象保存到数据库中&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; mongoengine &lt;span style="color:#f92672"&gt;import&lt;/span&gt; connect
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;connect(&lt;span style="color:#e6db74"&gt;&amp;#39;tumblelog&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;save()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;to_mongo&lt;/code&gt; 可以得到 SON 对象&lt;/p&gt;</description></item><item><title>Matplotlib学习笔记：绘制等值线和填充图</title><link>https://blog.perillaroc.wang/post/2018/2018-09-23-matplotlib-notebook-draw-contour/</link><pubDate>Sun, 23 Sep 2018 15:41:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-09-23-matplotlib-notebook-draw-contour/</guid><description>&lt;p&gt;等值线和填充图属于同一种类型的图形。&lt;/p&gt;
&lt;p&gt;气象上的填充图的数据包括两个部分：格点数据和地图数据。格点数据是一个二维数组，每个点都有一个经纬度坐标，对应地图上的一个点。地图是固定的，通常由绘图库本身提供。&lt;/p&gt;
&lt;p&gt;填充图的绘图包括两个方面：绘制地图，在地图上绘制填充图。绘制地图涉及到确定地图投影以及绘制地图的哪些元素。绘制填充图包括样式、色表、等值线计算等等。&lt;/p&gt;
&lt;p&gt;Matplotlib 库提供&lt;code&gt;contourf&lt;/code&gt;函数绘制二维数组的填充图，提供&lt;code&gt;contour&lt;/code&gt;函数绘制等值线图。&lt;/p&gt;
&lt;p&gt;Cartopy 库提供地图和投影功能。&lt;/p&gt;
&lt;p&gt;Numpy 库提供表示格点数据的数据结构。&lt;/p&gt;
&lt;p&gt;结合上面三个库，就可以绘制气象上的填充图。&lt;/p&gt;
&lt;h2 id="准备环境"&gt;准备环境&lt;/h2&gt;
&lt;p&gt;安装需要的 python 库：matplotlib、cartopy 和 numpy。&lt;/p&gt;
&lt;p&gt;我要绘制的数据保存在 GRIB2 格式的文件中，所以还需要安装解码 GRIB2 数据的库，例如 eccodes。&lt;/p&gt;
&lt;p&gt;这里我使用基于 eccodes 开发的 python3 绑定库 &lt;a href="https://github.com/perillaroc/nuwe-pyeccodes"&gt;nuwe-pyeccodes&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="准备数据"&gt;准备数据&lt;/h2&gt;
&lt;p&gt;定位想要绘图的 GRIB2 消息。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;some-file-dir/gmf.gra.2018081800003.grb2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;message_number &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;85&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_file &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nuwe_pyeccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;GribFileHandler()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;openFile(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, message_number):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grib_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_file&lt;span style="color:#f92672"&gt;.&lt;/span&gt;next()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构造经纬度坐标。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;left_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;right_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lon_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;iDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getLong(&lt;span style="color:#e6db74"&gt;&amp;#39;Ni&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lon_array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(left_lon, right_lon &lt;span style="color:#f92672"&gt;+&lt;/span&gt; lon_step &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, lon_step)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;top_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bottom_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lat_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getDouble(&lt;span style="color:#e6db74"&gt;&amp;#39;jDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ny &lt;span style="color:#f92672"&gt;=&lt;/span&gt; grib_message&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getLong(&lt;span style="color:#e6db74"&gt;&amp;#39;Nj&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lat_array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;arange(top_lat, bottom_lat &lt;span style="color:#f92672"&gt;-&lt;/span&gt; lat_step &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;lat_step)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lons, lats &lt;span style="color:#f92672"&gt;=&lt;/span&gt; np&lt;span style="color:#f92672"&gt;.&lt;/span&gt;meshgrid(lon_array, lat_array)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;构造二维数组。&lt;/p&gt;</description></item><item><title>rabbitmq执行长时间任务</title><link>https://blog.perillaroc.wang/post/2018/2018-08-13-long-time-job-in-rabbitmq/</link><pubDate>Mon, 13 Aug 2018 12:49:29 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-08-13-long-time-job-in-rabbitmq/</guid><description/></item><item><title>python click 参数检测与子命令</title><link>https://blog.perillaroc.wang/post/2018/2018-08-09-python-click-option-check-and-subcommand/</link><pubDate>Thu, 09 Aug 2018 21:01:31 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-08-09-python-click-option-check-and-subcommand/</guid><description/></item><item><title>ecCodes学习笔记：GRIB2文件插值与裁剪</title><link>https://blog.perillaroc.wang/post/2018/2018-08-04-eccodes-notebook-grib2-file-interpolation-and-cropping/</link><pubDate>Sat, 04 Aug 2018 23:26:22 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-08-04-eccodes-notebook-grib2-file-interpolation-and-cropping/</guid><description>&lt;p&gt;&lt;strong&gt;使用 ecCodes 和 scipy 实现对 GRIB2 文件的裁剪与插值&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ecCodes 提供 Python API，可以方便地解码 GRIB2 数据。&lt;br&gt;
GRIB2 文件由多个消息构成，循环使用 &lt;code&gt;codes_grib_new_from_file()&lt;/code&gt; 方法，逐个读取 GRIB2 消息。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(file_path, &lt;span style="color:#e6db74"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grib_message &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_grib_new_from_file(f)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; grib_message &lt;span style="color:#f92672"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ecCodes 内部使用 NumPy 保存数据，支持 SciPy 技术栈。
scipy 的 interpolation 包提供多种插值方法，支持从一维到n维的各类数据。
GRIB2 数据可以看做二维数据，因此可以使用 scipy 实现裁剪与插值。&lt;/p&gt;
&lt;h2 id="获取源数据信息"&gt;获取源数据信息&lt;/h2&gt;
&lt;p&gt;使用 ecCodes 获取 GRIB 数据的网格信息&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;left_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;right_lon &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;longitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lon_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;iDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;Ni&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;top_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfFirstGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bottom_lat &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;latitudeOfLastGridPointInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lat_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;jDirectionIncrementInDegrees&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ny &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get(grib_message, &lt;span style="color:#e6db74"&gt;&amp;#39;Nj&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;orig_values &lt;span style="color:#f92672"&gt;=&lt;/span&gt; eccodes&lt;span style="color:#f92672"&gt;.&lt;/span&gt;codes_get_values(grib_message)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GRIB2 数据点保存顺序由 scanning mode 值决定。
NWPC 生成的 GRIB2 数据 scanning mode 都是 0，也就是经度从小到大，纬度从大到小，同纬度的点排在一起（按行排列）。
下面只考虑该类型的数据。&lt;/p&gt;</description></item><item><title>ecCodes学习笔记：eccodes无法读取sample文件</title><link>https://blog.perillaroc.wang/post/2018/2018-06-30-eccodes-notebook-cant-read-sample-files/</link><pubDate>Sat, 30 Jun 2018 17:05:20 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-06-30-eccodes-notebook-cant-read-sample-files/</guid><description>&lt;p&gt;Windows下使用 MSVC 编译的 eccodes 在执行 codes_grib_handle_new_from_samples 时返回空指针。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;string sample_filename &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;regular_ll_pl_grib2&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;codes_handle&lt;span style="color:#f92672"&gt;*&lt;/span&gt; handle &lt;span style="color:#f92672"&gt;=&lt;/span&gt; codes_grib_handle_new_from_samples(&lt;span style="color:#66d9ef"&gt;nullptr&lt;/span&gt;, sample_filename.c_str());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="故障排查"&gt;故障排查&lt;/h2&gt;
&lt;p&gt;已设置ECCODES相关的环境变量 ECCODES_DEFINITION_PATH 和 ECCODES_SAMPLES_PATH。&lt;br&gt;
使用Visual Studio跟踪调试，发现问题出在 grib_templates.c 文件的如下函数中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;grib_handle&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;grib_external_template&lt;/span&gt;(grib_context&lt;span style="color:#f92672"&gt;*&lt;/span&gt; c,&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;base &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c&lt;span style="color:#f92672"&gt;-&amp;amp;&lt;/span&gt;gt;grib_samples_path;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; buffer[&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buffer;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; grib_handle &lt;span style="color:#f92672"&gt;*&lt;/span&gt;g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;base) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; NULL;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;base)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;*&lt;/span&gt;base &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; try_template(c,buffer,name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(g) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; g;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; buffer;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; base&lt;span style="color:#f92672"&gt;++&lt;/span&gt;; &lt;span style="color:#75715e"&gt;/*advance past delimiter*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;p&lt;span style="color:#f92672"&gt;++&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;base&lt;span style="color:#f92672"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; try_template(c,buffer,name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 c-&amp;gt;grib_samples_path 是 ECCODES_SAMPLES_PATH 中设置目录，因为 ECCODES_SAMPLES_PATH 中可以设置多个目录，所以需要循环检测多个目录，是否存在名称为 name 的 sample 文件。问题就出在分解多个目录的代码上&lt;/p&gt;</description></item><item><title>使用 VS 2017 和 Qt 5.9 编译 VTK 8.X</title><link>https://blog.perillaroc.wang/post/2018/2018-06-13-build-vtk-8-using-vs-2017-and-qt-5-9/</link><pubDate>Wed, 13 Jun 2018 16:40:18 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-06-13-build-vtk-8-using-vs-2017-and-qt-5-9/</guid><description/></item><item><title>Vue.js中使用D3.js绘制SVG图形</title><link>https://blog.perillaroc.wang/post/2018/2018-06-06-draw-svg-image-using-d3js-in-vuejs/</link><pubDate>Wed, 06 Jun 2018 22:08:38 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-06-06-draw-svg-image-using-d3js-in-vuejs/</guid><description>&lt;p&gt;使用 D3.js 绘制 SVG 图形通常使用 D3 的 API 动态添加 SVG 元素并绘制元素。在 Vue.js 中依然可以采用该方法创建 SVG 图形。&lt;br&gt;
类似 React，Vue.js 也支持 ref 属性。在 template 中定义 ref 属性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Chart
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ref&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;chart_canvas_ref&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;template&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 script 中可以使用如下方式通过 ref 访问元素：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;$refs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;chart_canvas_ref&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;D3.js 的 d3.select 支持 DOM 节点作为参数，因此创建 svg 的方法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;svg_node&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;select&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;$refs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;chart_canvas_ref&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;svg&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;width&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;width&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;height&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;height&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后面就可以在 svg_node 上使用 D3.js 的 API 创建 svg 元素。&lt;/p&gt;</description></item><item><title>ecFlow 远程执行任务</title><link>https://blog.perillaroc.wang/post/2018/2018-02-07-run-remote-task-in-ecflow/</link><pubDate>Wed, 07 Feb 2018 15:52:00 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-02-07-run-remote-task-in-ecflow/</guid><description>&lt;p&gt;ecflow 官方网站上远程执行任务的例子是假定远程服务器与 ecflow server 所在的服务器共享磁盘（例如使用 NAS）。但实际中远程服务器的文件系统往往独立于任务控制服务器，因此需要编写额外的脚本来远程执行任务。&lt;/p&gt;
&lt;p&gt;远程执行任务需要注意下面几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;任务脚本&lt;/li&gt;
&lt;li&gt;执行命令&lt;/li&gt;
&lt;li&gt;与 ecflow 的通讯&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;任务脚本是在 ecflow server 所在的服务器生成的，需要拷贝到远程服务器上执行。&lt;/p&gt;
&lt;p&gt;远程执行命令可以通过 ssh 调用远程服务器上的命令实现。&lt;/p&gt;
&lt;p&gt;ecflow_client 提供与远程 ecflow 服务通讯的功能，需要设置 &lt;code&gt;ECF_NODE&lt;/code&gt; 和 &lt;code&gt;ECF_PORT&lt;/code&gt; 变量。要确保任务执行的环境能访问到 ECF_NODE 节点上的 ECF_PORT 端口。&lt;/p&gt;
&lt;p&gt;为了实现远程执行任务，需要对 suite 定义、脚本环境变量、提交作业的命令等部分进行修改。&lt;/p&gt;
&lt;h2 id="suite-定义"&gt;suite 定义&lt;/h2&gt;
&lt;p&gt;为了使用 ssh 连接，需要定义远程服务器的用户名 ip 地址（端口号可以省略）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;suite&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;REMOTE_USER&amp;#34;&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;remote_user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;suite&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;REMOTE_HOST&amp;#34;&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;remote_host)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定义拷贝作业脚本的根路径，对应本地的作业脚本根路径 &lt;code&gt;ECF_HOME&lt;/code&gt;。
拷贝文件时将 &lt;code&gt;ECF_HOME&lt;/code&gt; 替换为 &lt;code&gt;REMOTE_ECF_HOME&lt;/code&gt;，得到的就是远程服务器上文件的路径。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;suite&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;ECF_HOME&amp;#34;&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ecf_home)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;suite&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;REMOTE_ECF_HOME&amp;#34;&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;remote_ecf_home)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ecflow server 节点自带的 &lt;code&gt;ECF_NODE&lt;/code&gt; 变量值可能是服务器的 hostname，远程服务器往往无法识别。所以最好使用 IP 地址定义一个记录 ecflow server 节点的变量，例如 &lt;code&gt;REMOTE_ECF_NODE&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;suite&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;ECF_PORT&amp;#34;&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ecf_port)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;suite&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add_variable(&lt;span style="color:#e6db74"&gt;&amp;#34;REMOTE_ECF_NODE&amp;#34;&lt;/span&gt;, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ecf_node)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设定 &lt;code&gt;ECF_JOB_CMD&lt;/code&gt;，使用一个脚本实现远程提交作业。&lt;/p&gt;</description></item><item><title>ecCodes学习笔记：Windows下编译ecCodes</title><link>https://blog.perillaroc.wang/post/2018/2018-01-09-eccodes-notebook-build-under-windows/</link><pubDate>Tue, 09 Jan 2018 13:03:28 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-01-09-eccodes-notebook-build-under-windows/</guid><description>&lt;p&gt;ecCodes 是由 ECMWF 开发的气象数据解码软件，支持 GRIB 和 BURF 格式，是ECMWF 之前开发的 GRIB 解码工具 GRIB-API 的升级版。&lt;br&gt;
与 GRIB-API 一样，ecCodes 提供 WINDOWS 下缩减版的编译方式，只包含核心库和一些命令行工具，不支持 Fortran 和 Python 接口。下面介绍下 Windows 版的编译方式。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;GRIB 2 文件一般使用 JPEG 2000 算法压缩数据，所以需要 JPEG 解码库 &lt;a href="https://github.com/mdadams/jasper"&gt;Jasper&lt;/a&gt; 或 &lt;a href="https://github.com/uclouvain/openjpeg"&gt;OpenJPEG&lt;/a&gt;。&lt;br&gt;
2.X 版本的 Jasper 支持 CMake，可以直接在 Windows 下编译。OpenJPEG 同样支持 CMake 编译，而且还提供 Windows 的预编译包，可以直接使用。&lt;br&gt;
下面使用 OpenJPEG 的二进制包编译 ecCodes。&lt;/p&gt;
&lt;h2 id="编译-grib_api_lib"&gt;编译 grib_api_lib&lt;/h2&gt;
&lt;p&gt;ecCodes 源码目录中包含 Visual Studio 的解决方案文件，位于 windows/msvc/grib_api.sln。我使用 Visual Studio 2017 打开。&lt;br&gt;
默认平台方案是 Win32，建议新建 x64 方案平台，编译 64 位版本。&lt;br&gt;
在 grib_api_lib 中设置预处理器变量：&lt;/p&gt;</description></item><item><title>2017年个人总结</title><link>https://blog.perillaroc.wang/post/2018/2018-01-07-2017-summary/</link><pubDate>Sun, 07 Jan 2018 20:14:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-01-07-2017-summary/</guid><description>&lt;p&gt;翻看博客中文章，上一篇像样的个人总结还是2014年的。15年虽然写了一些话，但连标题都写成16年的，文章的用心程度可想而知。而今年年初一直想写一篇对2016年的总结，结果拖到春节后还没有动笔，就不了了之了。对于刚结束的2017年还是要写一篇态度认真的个人总结。最近工程博士答辩给我带来巨大的压力，我需要锻炼一下自己的心态调整能力，本篇个人总结要赶在18年的第一周内完成。&lt;/p&gt;
&lt;h2 id="人生有三喜"&gt;人生有三喜&lt;/h2&gt;
&lt;p&gt;2017年最重要的经历当然就是我与心爱的她步入婚礼的殿堂，从此我不再是一个人，而是一家的一部分，需要承担家庭的责任，需要从一个丈夫、一个家庭的角度考虑问题。感谢父母对我们的养育，感谢爱人对我的关爱，我也会更加用心地经营我们的家庭。&lt;/p&gt;
&lt;img src="http://wx1.sinaimg.cn/large/4afdac38ly1fn8ajuvj8jj20sg0iz0z5.jpg" width="1024" height="683" class="alignnone" /&gt; 
&lt;h2 id="诗和远方"&gt;诗和远方&lt;/h2&gt;
&lt;p&gt;诗只是标题，远方才是目标。远方是爱人的理想，我也渐渐爱上这个神奇的词汇。&lt;br&gt;
今年清明，我们去了香港，去了这个无数次出现在电影和电视剧中的地方。品尝了港式美食，浏览了商业中心，寻觅了街道市场，也游玩了迪士尼乐园。除了人多点儿，价高点儿，香港还是个挺值得一逛的地方。&lt;br&gt;
十月下旬，我们去了泰国的普吉岛，深刻感受了大海的气息。从普吉老城到海边沙滩，从佛教庙宇到特色秀场，充分感受了一把异国他乡的风土人情。这是一个以旅游业为支柱的地方，可以看到成熟的旅游业态。我们还出海去了斯米兰岛、攀牙湾和蜜月岛，虽然爱人吐得一塌糊涂，我们下次一定还要出海看美丽的海岛风景。&lt;/p&gt;
&lt;h2 id="第一个五年"&gt;第一个五年&lt;/h2&gt;
&lt;p&gt;从2013年入职至今，五年时间将我从一个对未来充满理想的热血青年变成一名陷入日常重复性工作的麻木青年。都说体制内犹如温水煮青蛙，我觉得自己快要被煮熟了。之前保留的些许创造力被消耗殆尽，去年我再也没有创新性的贡献，而这对于立志于走技术路线的我来说尤为致命。与科学研究类似，技术人员一旦无法保持创新的趋势，就会淹没在繁杂的琐事中，职场再无发展前景。从最新的研究成果寻找灵感是获得创新性的一种方式，而我去年恰恰缺乏对新技术、新趋势的了解，对气象行业的最新进展也没有足够的关注，今年必须要注重这方面的训练。 下面还是进入本节的正题，总结下去年我的工作情况。&lt;/p&gt;
&lt;h3 id="职场发展"&gt;职场发展&lt;/h3&gt;
&lt;p&gt;去年年初赶上一波红利，单位要提拔年轻员工，推选年龄35岁以下、硕士以上学历的年轻人为副科长，而我们科符合条件的就我一人，因此我就幸运地被选为副科长，试用期一年。不过，除了每周参加处室例会和编写科长安排的文字材料外，工作上没什么改变，工作方式依然和之前一样，每人负责各自的任务。总之，做好自己的工作是最重要的，可惜这点上我不算优秀。&lt;br&gt;
去年我花了三个月的时间，将前年开发移动端维护平台的技术写成一篇论文，投给《气象科技》。不过直到现在也没有准确的消息该论文是否被接收，审稿的效率令人担忧。青年基金项目需要一篇核心期刊论文，因此今年必须要写一篇关于分布式调度系统的论文。但去年这方面的工作没有太多创新性，今年我将面临巨大的挑战，必须投入足够的精力拿出有价值的成果。或许我还可以在移动端维护平台方面开启新的论文方向，引入新技术实现新功能。&lt;br&gt;
去年我去郑州参加了中国气象学会年会，并在分会场做了一篇报告《基于SMS的数值预报运行日志分析系统》。在见识郑州遍地工地快速发展的同时，拿到一篇会议论文，走出评高工的第一步。&lt;/p&gt;
&lt;h3 id="工作任务"&gt;工作任务&lt;/h3&gt;
&lt;h4 id="诊断平台"&gt;诊断平台&lt;/h4&gt;
&lt;p&gt;从入职起至今都在开发物理过程诊断软件平台，依然没法拿出一个可以试用的版本。说实话今年我在这上面投入的精力太少，我总会逃避自己无法控制的工作和有困难的工作。我的团队合作能力有待提高。作为现在工作中唯一需要团队协作的项目，我却难以专注地研究下去，白白浪费锻炼项目管理能力的机会，也在浪费树立自己核心竞争力的机会。当然，我总愿意寻找外部原因来逃避寻找自身的问题。这个项目到现在这个地步，有诸多原因，我应该好好想一想这个项目接下来到底该做什么，好像几年前我就在总结中这样写，但现在我依然这样说，真是个悲剧。提到诊断软件，就不得不说单位目前的项目开发，去年一年我看明白了一些事情，有些事情不是我能决定的，所以我只能尽量不参与这些。期望现有的方式能做出有价值的成果，实在是一件颇具挑战性的任务。所以，我倾向于尽量缩小外包公司的任务量，指定明确的任务目标，如果再无法顺利完成，我只能放弃这部分工作了。&lt;/p&gt;
&lt;h4 id="运维工具"&gt;运维工具&lt;/h4&gt;
&lt;p&gt;开发运维工具依旧是我的最爱，毕竟值班要使用到。2017年我更加注重不同项目的关联，将通用的功能放到底层模型库中，并在这些模型库的基础上开发运维工具。&lt;/p&gt;
&lt;h5 id="底层模型库"&gt;底层模型库&lt;/h5&gt;
&lt;p&gt;包括工作流模型库（&lt;a href="https://github.com/perillaroc/nwpc-work-flow-model"&gt;nwpc-work-flow-model&lt;/a&gt;）和HPC信息模型库（&lt;a href="https://github.com/perillaroc/nwpc-hpc-model"&gt;nwpc-hpc-model&lt;/a&gt;）。&lt;br&gt;
nwpc-work-flow-model 包括对业务系统的调度软件SMS的模拟。&lt;br&gt;
nwpc-hpc-model 包括对高性能计算机的作业调度软件 LoadLeveler 状态的模拟。&lt;/p&gt;
&lt;h5 id="移动监控工具"&gt;移动监控工具&lt;/h5&gt;
&lt;p&gt;这是2015-2016年度最重要的工作成果，虽然缺乏切实的成果证明，但对于值班工作的帮助有目共睹。2017年主要工作是将重复性强且容易忘记的人工操作变为自动化工作，降低运维的工作量，提高自动化水平。主要新增以下两个异常检测功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SMS节点异常&lt;/li&gt;
&lt;li&gt;LoadLeveler队列异常&lt;/li&gt;
&lt;/ul&gt;
&lt;h6 id="sms节点异常"&gt;SMS节点异常&lt;/h6&gt;
&lt;p&gt;检测节点变量是否正常，主要检测当前系统的日期时候是当前日期。&lt;br&gt;
检测节点状态是否正常，主要检测某个系统的某个时次是否按时启动。&lt;br&gt;
&lt;img class="alignnone" src="http://wx2.sinaimg.cn/large/4afdac38ly1fn7z01joqrj21790hyafh.jpg" alt="" width="1557" height="646" /&gt;&lt;/p&gt;
&lt;h6 id="loadleveler队列检测"&gt;LoadLeveler队列检测&lt;/h6&gt;
&lt;p&gt;检测长时间运行的作业，当前有以下两个规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nwp, nwp_qu, nwp_pd, nwp_sp业务户头下运行时间超过12小时&lt;/li&gt;
&lt;li&gt;nwp_pd户头下upload作业运行超过4小时&lt;/li&gt;
&lt;/ul&gt;
&lt;img class="alignnone" src="http://wx3.sinaimg.cn/large/4afdac38ly1fn7z6txo32j20xo0hegrb.jpg" alt="" width="1212" height="626" /&gt; 
这两个功能使用 Celery beat 实现定时调用。目前各个检测任务是通过配置文件定义的静态任务，一旦 Celery 服务启动就无法更改，2018年计划引入动态任务。
&lt;h5 id="实时监控网页"&gt;实时监控网页&lt;/h5&gt;
&lt;p&gt;2017年我还学习了Prometheus，并将Prometheus的数据在Grafana中显示，配置了高性能计算机的实时监控网页。&lt;br&gt;
&lt;img class="alignnone" src="http://wx4.sinaimg.cn/large/4afdac38ly1fn7z9jhsn3j21kw0s514v.jpg" alt="" width="2048" height="1013" /&gt;&lt;br&gt;
获取得高性能计算机状态包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LoadLeveler队列：各个class的详情&lt;/li&gt;
&lt;li&gt;用户磁盘空间限额：业务账户的磁盘空间使用情况&lt;/li&gt;
&lt;li&gt;磁盘空间：HPC磁盘空间使用情况&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;获取高性能计算机状态的 exporter 详情见 &lt;a href="https://github.com/perillaroc/nwpc-hpc-exporter"&gt;nwpc-hpc-exporter&lt;/a&gt; 项目。该项目还提供各个 exporter 的 docker 封装，方便使用。&lt;/p&gt;
&lt;h5 id="loadleveler命令行工具"&gt;LoadLeveler命令行工具&lt;/h5&gt;
&lt;p&gt;2016年我开发了一款桌面软件提供对 LoadLeveler 队列的查询和操作功能，但单独的软件使用不太方便，因此2017年我开发了能在高性能计算机上使用的 LoadLeveler 命令行工具，封装业务值班常用的 LoadLeveler 查询操作。包括：&lt;/p&gt;</description></item><item><title>大日志文件中查找日志条目</title><link>https://blog.perillaroc.wang/post/2018/2018-01-03-search-record-from-huge-log-file/</link><pubDate>Wed, 03 Jan 2018 14:05:09 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2018/2018-01-03-search-record-from-huge-log-file/</guid><description>&lt;p&gt;数值预报业务系统所使用的调度软件 SMS 的日志保存文本文件中，日志结构如下所示：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# MSG:[04:27:43 8.9.2017] alter:/meso_post/00/meso_chartos/rundir/cn_plot_10m_wind/cn_plot_10m_wind_sep_020 [variable] by nwp_pd@53063265
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;分析系统运行情况时，需要找到指定日期范围内的所有日志。
解析日志条目时，先找到条目中的日期字符串，再将其转为日期对象，判断是否满足条件。&lt;br&gt;
从日志条目中提取时间的函数如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_date_from_line&lt;/span&gt;(line):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start_pos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; end_pos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find(&lt;span style="color:#e6db74"&gt;&amp;#39;]&amp;#39;&lt;/span&gt;, start_pos)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time_string &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line[start_pos:end_pos]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; date_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;datetime&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strptime(time_string, &lt;span style="color:#e6db74"&gt;&amp;#39;%H:%M:%S &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.%m.%Y&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; line_date &lt;span style="color:#f92672"&gt;=&lt;/span&gt; date_time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;date()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; line_date
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面首先介绍定位日志行数的基本方法。&lt;/p&gt;
&lt;h2 id="基本方法"&gt;基本方法&lt;/h2&gt;
&lt;p&gt;Python 中读取文本文件最常用的方式就是遍历 &lt;code&gt;file&lt;/code&gt; 对象，逐行读取：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(file_path, &lt;span style="color:#e6db74"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; line &lt;span style="color:#f92672"&gt;in&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; do_something(line)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对应本文就是逐行解析日志条目，先寻找起始日期，再寻找结束日期。
但对于大日志文件，逐行读取的效率太低。&lt;/p&gt;
&lt;p&gt;例如一个 1GB 的日志文件，共 840 多万行，日期从 2017 年 8 月 4 日到 2017 年 9 月 8 日。
在其中寻找 2017.09.01 至 2017.09.04 对应的行数耗时 137 秒。&lt;/p&gt;</description></item><item><title>使用Immutable.js更新Redux应用——简单方法</title><link>https://blog.perillaroc.wang/post/2017/2017-12-15-using-immutablejs-to-update-redux-application-simple-way/</link><pubDate>Fri, 15 Dec 2017 14:24:24 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-12-15-using-immutablejs-to-update-redux-application-simple-way/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;复杂 Redux 应用的 State 可能会有很深的层次，比如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;initial_state&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;status&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;is_fetching&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;last_updated&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;repo_list&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#a6e22e"&gt;owner&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;nwp_xp&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;repo&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;nwpc_op&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#a6e22e"&gt;owner&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;nwp_xp&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;repo&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;nwpc_qu&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;config_file_path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setup_env&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;status&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;unknown&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;load_log&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;repos&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;reducer 在修改 state 时，需要生成一个新的对象，而一种原生 JavaScript 复制对象的方法是使用 &lt;code&gt;Object.assign()&lt;/code&gt; 生成新的对象，但 &lt;code&gt;Object.assign&lt;/code&gt; 只能修改对象第一层次的属性。&lt;/p&gt;
&lt;p&gt;想要修改更深层次的属性，可以对层次树上的所有对象使用 &lt;code&gt;Obejct.assign&lt;/code&gt;，比如在上述 state 中修改 &lt;code&gt;load_log.repos&lt;/code&gt; 的属性&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(state, payload) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let load_log &lt;span style="color:#f92672"&gt;=&lt;/span&gt; state&lt;span style="color:#f92672"&gt;.&lt;/span&gt;load_log;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let repos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; load_log&lt;span style="color:#f92672"&gt;.&lt;/span&gt;repos;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let key &lt;span style="color:#f92672"&gt;=&lt;/span&gt; payload&lt;span style="color:#f92672"&gt;.&lt;/span&gt;key;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let new_repo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(key &lt;span style="color:#f92672"&gt;in&lt;/span&gt; repos){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_repo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assign({}, repos[key], payload&lt;span style="color:#f92672"&gt;.&lt;/span&gt;value);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_repo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assign({}, payload&lt;span style="color:#f92672"&gt;.&lt;/span&gt;value);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let new_repos &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assign({}, repos);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_repos[key] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new_repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let new_load_log &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assign({}, load_log, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; repos: new_repos
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let new_state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;assign({}, state, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; load_log: new_load_log
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; new_state;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述是我能想到的方式，过于繁琐，缺乏美感，并且编写容易出错。&lt;/p&gt;</description></item><item><title>批量执行任务：使用QtConcurrent实现</title><link>https://blog.perillaroc.wang/post/2017/2017-12-07-batch-execution-using-qtconcurrent/</link><pubDate>Thu, 07 Dec 2017 20:03:43 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-12-07-batch-execution-using-qtconcurrent/</guid><description>&lt;p&gt;批量执行一系列任务是软件中常见的需求，通常采用并行执行多个任务的方式加快速度。
比如使用下载软件下载多个文件时，下载软件会根据用户设置，同时下载队列中的几个文件，每当一个下载任务结束时，会自动启动下一个下载任务。&lt;/p&gt;
&lt;p&gt;本文介绍如何使用 QtConcurent 实现批量执行任务的功能。下面的场景来自下载小说的软件。&lt;/p&gt;
&lt;h2 id="方案"&gt;方案&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;QtConcurrent::map&lt;/code&gt; 执行批量任务。
&lt;code&gt;QtConcurrent::map&lt;/code&gt; 使用全局线程池（来自&lt;code&gt;QThreadPool::globalInstance&lt;/code&gt;）来执行程序，同时执行程序的个数由全局线程池设置的线程数决定。&lt;br&gt;
同时，&lt;code&gt;QtCocurrent::map&lt;/code&gt; 使用 &lt;code&gt;QFuture&lt;/code&gt; 返回异步计算结果，我们可以使用 &lt;code&gt;QFutureWatcher&lt;/code&gt; 与 &lt;code&gt;QFuture&lt;/code&gt; 的连接实现与任务的交互。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;首先设置全局线程池的线程个数，例如设置4个线程。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QThreadPool&lt;span style="color:#f92672"&gt;::&lt;/span&gt;globalInstance()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setMaxThreadCount(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建对任务进行监控的 &lt;code&gt;QFutureWatcher&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QFutureWatcher&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; future_watcher;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;准备需要批量执行的任务，比如下面下载小说章节的任务 &lt;code&gt;DownloadTask&lt;/code&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QVector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;downloadTask&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; download_tasks_;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;novel_content_model_&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;rowCount(); i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DownloadTask task;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task.name_ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; novel_content_model_&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;item(i, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;text();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task.link_ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; novel_content_model_&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;item(i, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;text();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task.directory_ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; local_directory;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task.task_no_ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; download_tasks_.push_back(task);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开始执行批量任务:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;future_watcher_.setFuture(QtConcurrent&lt;span style="color:#f92672"&gt;::&lt;/span&gt;map(download_tasks_, [&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;](&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; DownloadTask &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;task){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 执行任务，省略代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;QtConcurrent::map&lt;/code&gt; 会使用全局线程池自动执行所有任务。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QFutureWatcher&lt;/code&gt; 可以暂停或恢复任务的执行。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;future_watcher_.setPaused(checked);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="未来计划"&gt;未来计划&lt;/h2&gt;
&lt;p&gt;上面介绍使用 QtConcurrent 可以实现简单的批量执行任务功能。
但因为 QtConcurrent 只能使用全局线程池，缺乏更精细的控制手段，所以后续计划使用自定义的 QThreadPool 实现批量下载功能。&lt;/p&gt;</description></item><item><title>制作EPUB电子书</title><link>https://blog.perillaroc.wang/post/2017/2017-12-01-create-epub-book/</link><pubDate>Fri, 01 Dec 2017 22:28:15 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-12-01-create-epub-book/</guid><description>&lt;p&gt;之前一篇博文《&lt;a href="https://blog.perillaroc.wang/post/2017/2017-06-14-create-ebook-for-online-novel/"&gt;制作网络小说的电子书&lt;/a&gt;》中下载 HTML 网页，并使用 &lt;a href="https://calibre-ebook.com/"&gt;calibre&lt;/a&gt; 制作 epub 电子书。
如此制作电子书需要安装体积不算小巧的软件，不太方便。
本文介绍使用 Python 库 ebooklib 制作 EPUB 电子书的方法。&lt;/p&gt;
&lt;h2 id="为什么是epub格式"&gt;为什么是EPUB格式？&lt;/h2&gt;
&lt;p&gt;我的 Kindle 中都是 MOBI 格式的电子书，但为什么不直接制作 MOBI 的电子书，这样就不需要格式转换了。
因为 MOBI 格式不开源，能制作 MOBI 格式图书的库不多。
看过一些制作 MOBI 格式的库，使用 Amazon 提供的转换程序生成 MOBI 书籍。
目前还缺少有效的方式直接生成 MOBI 格式，所以我先选择 EPUB 格式，再使用 Calibre 转成 MOBI 格式。&lt;/p&gt;
&lt;h2 id="准备工作"&gt;准备工作&lt;/h2&gt;
&lt;p&gt;需要将电子书的每个章节保存成一个单独的HTML文件，可以使用《&lt;a href="https://blog.perillaroc.wang/post/2017/2017-06-14-create-ebook-for-online-novel/"&gt;制作网络小说的电子书&lt;/a&gt;》和《[使用Python下载网络小说](https://blog.perillaroc.wang/post/2017/2017-11-29-download-online-novel-using-python/》提到的方法制作电子书。
另外需要准备章节目录，至少包括每个章节的标题和HTML文件位置。
例如，可以使用下面的数据结构：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;皇甫奇&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;contents&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;./4641557.html&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;link&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;//www.yunlaige.com/html/9/9313/4641557.html&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;作者语&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;./4641558.html&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;link&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;//www.yunlaige.com/html/9/9313/4641558.html&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;序章 纪元的毁灭和开始&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;file_path&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;/4641559.html&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;link&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;//www.yunlaige.com/html/9/9313/4641559.html&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;第一章 杨纪&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;帝御山河最新章节&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述文件可以由下载网页的程序自动生成，保存在网页目录下。&lt;/p&gt;</description></item><item><title>使用Python下载网络小说</title><link>https://blog.perillaroc.wang/post/2017/2017-11-29-download-online-novel-using-python/</link><pubDate>Wed, 29 Nov 2017 20:58:31 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-11-29-download-online-novel-using-python/</guid><description>&lt;blockquote&gt;
&lt;p&gt;与之前一篇博文重复，写本文时忘记了，请参看《&lt;a href="https://blog.perillaroc.wang/post/2017/2017-06-14-create-ebook-for-online-novel/"&gt;制作网络小说的电子书&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;作为一个网络小说资深盗版读者，从不会为了小说资源而发愁。
很久之前用过一款叫做《小说下载浏览器》的软件，集成强大的搜索、下载、制作功能，配上丰富的网址资源和模板，是我当时看小说的首选，可惜后来被封杀了。
最近使用一款叫做《追书神器》的APP，但已有明显的收费趋势，只能使用老版本。
所谓靠人不如靠己，说的就是应该自己写程序下载小说。
好在现在盗版小说网站遍地都是，想写个程序不难。&lt;/p&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;p&gt;下载小说分为两个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;获取目录&lt;/li&gt;
&lt;li&gt;获取章节内容&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面就以&lt;a href="//www.yunlaige.com/"&gt;云来阁&lt;/a&gt;为例，分别介绍这两个步骤。&lt;/p&gt;
&lt;h2 id="获取目录"&gt;获取目录&lt;/h2&gt;
&lt;p&gt;一般小说网站都有小说目录页，例如云来阁上的《五行天》目录页&lt;/p&gt;
&lt;p&gt;//www.yunlaige.com/html/18/18535/index.html&lt;/p&gt;
&lt;p&gt;首先需要使用 requests 获取目录页，并使用 BeautifulSoup 解析，留意网页的编码。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(url, proxies&lt;span style="color:#f92672"&gt;=&lt;/span&gt;proxy_config)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;bs_object &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BeautifulSoup(response&lt;span style="color:#f92672"&gt;.&lt;/span&gt;content, &lt;span style="color:#e6db74"&gt;&amp;#34;html.parser&amp;#34;&lt;/span&gt;, from_encoding&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;gb18030&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;目录页一般以表格（table）、列表（dd、dt）等形式列出所有章节。例如&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;table&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;border&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;align&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;center&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cellpadding&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;3&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cellspacing&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;contenttable&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;class&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;table&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;tr&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;8751561.html&amp;#34;&lt;/span&gt;&amp;gt;第一章 决定&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;8751562.html&amp;#34;&lt;/span&gt;&amp;gt;第二章 报道&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;8751563.html&amp;#34;&lt;/span&gt;&amp;gt;第三章 怒火&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;tr&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;table&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中每个 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 标签都代表一个章节，获取目录就是要找到该表格元素，抽取该节点下的所有 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 节点，组成目录。&lt;/p&gt;
&lt;p&gt;上面的表格有明显的 id，使用 &lt;code&gt;select_one&lt;/code&gt; 定位该表格，然后使用 &lt;code&gt;findAll&lt;/code&gt; 寻找所有的&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;节点。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;content_container_node &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bs_object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;select_one(&lt;span style="color:#e6db74"&gt;&amp;#39;#contenttable&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;link_nodes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; content_container_node&lt;span style="color:#f92672"&gt;.&lt;/span&gt;findAll(&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;针对每个 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 节点，可以得到章节标题和对应的网页地址。
其中使用节点的 &lt;code&gt;string&lt;/code&gt; 方法获取节点内的字符串。&lt;/p&gt;</description></item><item><title>Python列表排序</title><link>https://blog.perillaroc.wang/post/2017/2017-11-15-python-list-sorting/</link><pubDate>Wed, 15 Nov 2017 21:45:35 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-11-15-python-list-sorting/</guid><description>&lt;p&gt;Python 列表内置 &lt;code&gt;list.sort()&lt;/code&gt; 方法实现原地排序，同时 Python 还提供 &lt;code&gt;sorted()&lt;/code&gt; 函数返回对可迭代对象排序后的新列表。
下面介绍目前我对排序的使用。&lt;/p&gt;
&lt;h2 id="指定排序方式"&gt;指定排序方式&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;list.sort()&lt;/code&gt; 和 &lt;code&gt;sorted()&lt;/code&gt; 都有一个参数 key，指定一个函数，比较前，会在每个元素上会调用该函数。&lt;br&gt;
可以使用语言自带的函数，例如 &lt;code&gt;str.lower&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(&lt;span style="color:#e6db74"&gt;&amp;#34;This is a test string from Andrew&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split(), key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;str&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lower)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以使用 lambda 函数，例如针对某个特定的属性排序：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(student_tuples, key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; student: student&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;还可以使用自定义的函数，该函数以序列中的单个元素作为参数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sort_function&lt;/span&gt;(item):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; item&lt;span style="color:#f92672"&gt;.&lt;/span&gt;value
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(array, key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sort_function)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="多重排序"&gt;多重排序&lt;/h2&gt;
&lt;p&gt;key 只支持单个键排序，如果需要多重排序，则可以将多条件组成 tuple，再传给 key。
可以使用 &lt;code&gt;operator.attrgetter&lt;/code&gt; 获取多个属性值。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sorted(student_objects, key&lt;span style="color:#f92672"&gt;=&lt;/span&gt;attrgetter(&lt;span style="color:#e6db74"&gt;&amp;#39;grade&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;age&amp;#39;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;《&lt;a href="https://docs.python.org/3/howto/sorting.html"&gt;Sorting HOW TO&lt;/a&gt;》，关于列表排序的官方文档&lt;/p&gt;</description></item><item><title>测试使用SQLAlchemy的项目</title><link>https://blog.perillaroc.wang/post/2017/2017-08-31-test-project-using-sqlalchemy/</link><pubDate>Thu, 31 Aug 2017 10:46:59 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-08-31-test-project-using-sqlalchemy/</guid><description>&lt;p&gt;对使用 SQLAlchemy 连接数据库的项目进行单元测试，直接使用项目的数据库不利于测试，需要测试环境安装相应的数据库，很不方便。
python 集成的 sqlite 可以在内存中构建数据库，正好可以用来进行单元测试。
不过这样就必须考虑不同数据库SQL的兼容问题，无法使用特定数据库的独有 SQL 语句。&lt;/p&gt;
&lt;h2 id="构建测试数据库"&gt;构建测试数据库&lt;/h2&gt;
&lt;p&gt;SQLAlchemy 中使用 &lt;code&gt;sqlite://&lt;/code&gt; 表示内存中的 SQLite 数据库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sqlalchemy &lt;span style="color:#f92672"&gt;import&lt;/span&gt; create_engine
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sqlalchemy.orm &lt;span style="color:#f92672"&gt;import&lt;/span&gt; sessionmaker
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;engine &lt;span style="color:#f92672"&gt;=&lt;/span&gt; create_engine(&lt;span style="color:#e6db74"&gt;&amp;#34;sqlite://&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sessionmaker(bind&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Session()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Model&lt;span style="color:#f92672"&gt;.&lt;/span&gt;metadata&lt;span style="color:#f92672"&gt;.&lt;/span&gt;create_all(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;commit()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;Model&lt;/code&gt; 是整个数据库使用的 &lt;code&gt;Declarative&lt;/code&gt; 类。&lt;/p&gt;
&lt;h2 id="清空数据库"&gt;清空数据库&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;Model.metadata&lt;/code&gt; 清空数据库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Model&lt;span style="color:#f92672"&gt;.&lt;/span&gt;metadata&lt;span style="color:#f92672"&gt;.&lt;/span&gt;drop_all(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;下面是我的一个项目中使用 pytest 做单元测试的示例。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sqlalchemy &lt;span style="color:#f92672"&gt;import&lt;/span&gt; create_engine
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; sqlalchemy.orm &lt;span style="color:#f92672"&gt;import&lt;/span&gt; sessionmaker
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; nwpc_log_model.rdbms_model.models &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Model, User
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestUserTable&lt;/span&gt;(object):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setup_method&lt;/span&gt;(self, method):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine &lt;span style="color:#f92672"&gt;=&lt;/span&gt; create_engine(&lt;span style="color:#e6db74"&gt;&amp;#34;sqlite://&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sessionmaker(bind&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Session()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Model&lt;span style="color:#f92672"&gt;.&lt;/span&gt;metadata&lt;span style="color:#f92672"&gt;.&lt;/span&gt;create_all(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;commit()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;teardown_method&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Model&lt;span style="color:#f92672"&gt;.&lt;/span&gt;metadata&lt;span style="color:#f92672"&gt;.&lt;/span&gt;drop_all(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;engine)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_user_create&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; User()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;my_user&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add(user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;commit()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;query(User)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;filter(User&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_id &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query_user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; user_query&lt;span style="color:#f92672"&gt;.&lt;/span&gt;first()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; query_user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_id &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assert&lt;/span&gt; query_user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user_name &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;my_user&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Windows下使用pip安装包出错</title><link>https://blog.perillaroc.wang/post/2017/2017-08-02-pip-install-packages-has-error-on-windows/</link><pubDate>Wed, 02 Aug 2017 10:50:12 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-08-02-pip-install-packages-has-error-on-windows/</guid><description>&lt;p&gt;Windows 使用 pip 安装 python 库时会出现如下的错误：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Exception:
Traceback (most recent call last):
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\compat\__init__.py&amp;#34;, line 73, in console_to_str
 return s.decode(sys.__stdout__.encoding)
UnicodeDecodeError: &amp;#39;utf-8&amp;#39; codec can&amp;#39;t decode byte 0xa1 in position 42: invalid start byte
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\basecommand.py&amp;#34;, line 215, in main
 status = self.run(options, args)
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\commands\install.py&amp;#34;, line 342, in run
 prefix=options.prefix_path,
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\req\req_set.py&amp;#34;, line 784, in install
 **kwargs
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\req\req_install.py&amp;#34;, line 878, in install
 spinner=spinner,
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\utils\__init__.py&amp;#34;, line 676, in call_subprocess
 line = console_to_str(proc.stdout.readline())
 File &amp;#34;e:\tmp\python\env\lib\site-packages\pip\compat\__init__.py&amp;#34;, line 75, in console_to_str
 return s.decode(&amp;#39;utf_8&amp;#39;)
UnicodeDecodeError: &amp;#39;utf-8&amp;#39; codec can&amp;#39;t decode byte 0xa1 in position 42: invalid start byte
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是因为 windows 下使用的还是 gbk 编码，需要修改 pip 包下 &lt;code&gt;compat/__init__.py&lt;/code&gt; 代码，大致在 75 行&lt;/p&gt;</description></item><item><title>在应用中集成Python运行环境</title><link>https://blog.perillaroc.wang/post/2017/2017-07-20-embed-python-environment-in-application/</link><pubDate>Thu, 20 Jul 2017 16:10:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-07-20-embed-python-environment-in-application/</guid><description>&lt;p&gt;使用脚本来扩展程序一直是应用软件常用的模式，从Vim、Atom等软件，到诸如魔兽世界、无冬之夜等游戏，都为用户提供方便的插件扩展功能。
它们都将某种脚本语言集成到应用中，作为实现插件架构的核心语言，正是看中脚本语言易于使用、便于集成的优点。
作为一门目前广泛使用的脚本语言，Python 同样被用作插件语言，比如 sublime text 就使用 Python 开发插件。&lt;/p&gt;
&lt;p&gt;本文就介绍如何将 Python 运行环境集成到应用中。&lt;/p&gt;
&lt;p&gt;最简单的集成方式，就是将 Python 运行环境包含在应用中，直接是使用 python.exe 可执行文件运行 python 脚本。
但 Windows 下可以直接拷贝安装后的 Python 目录，但目录比较大。
从 Python 3.5 开始，Python 提供一个 zip 打包的 Embedded Distribution 环境，只包含最基本的 Python 运行环境，远远小于安装后的 Python 目录，更适合在应用中集成。
不过该环境不包含 pip，无法直接安装第三方库，需要进行一定的修改。&lt;/p&gt;
&lt;h2 id="修改pth文件"&gt;修改pth文件&lt;/h2&gt;
&lt;p&gt;Embedded Distribution 将 Python 标准库打包到 python3X.zip 文件中，并通过 &lt;code&gt;python36._pth&lt;/code&gt; 通知 python 解释器标准库的位置。
默认的 &lt;code&gt;python36._pth&lt;/code&gt; 文件如下&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;python36.zip
.
# Uncomment to run site.main() automatically
# import site
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;安装 pip 前，需要将最后一行的注释打开，提供对 site-packages 目录的支持。&lt;/p&gt;</description></item><item><title>使用git subtree管理子项目 v2</title><link>https://blog.perillaroc.wang/post/2017/2017-07-12-use-git-subtree-to-manage-sub-project-v2/</link><pubDate>Wed, 12 Jul 2017 14:55:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-07-12-use-git-subtree-to-manage-sub-project-v2/</guid><description>&lt;p&gt;之前一篇文章使用 &lt;code&gt;git subtree&lt;/code&gt; 命令创建子项目，参见《&lt;a href="https://blog.perillaroc.wang/post/2017/2017-07-12-use-git-subtree-to-manage-sub-project-v2/"&gt;使用git subtree管理子项目&lt;/a&gt;》。
Git 官方文档和 Github 的使用帮助中给出另外一种使用 subtree 创建子目录的方法，不再使用 &lt;code&gt;git subtree&lt;/code&gt; 命令，而在 pull 中使用 subtree 策略。&lt;/p&gt;
&lt;p&gt;与前文相似，下面在 nwpc-monitor-platform 项目中添加子项目 nwpc-hpc-model。&lt;/p&gt;
&lt;h2 id="建立关联"&gt;建立关联&lt;/h2&gt;
&lt;p&gt;在 nwpc-monitor-platform 中添加 nwpc-hpc-model 为远程分支。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/d/windroc/project/monitor/nwpc-monitor-platform (master)
$ git remote add -f hpc-model git@github.com:perillaroc/nwpc-hpc-model.git
Updating hpc-model
Enter passphrase for key &amp;#39;/c/Users/wangdp/.ssh/id_rsa&amp;#39;:
From github.com:perillaroc/nwpc-hpc-model
 * [new branch] master -&amp;gt; hpc-model/master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将 hpc-model 分支的历史合并到 master 分支中，这一步不改变本地文件，但可以为后续操作提供支持。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/d/windroc/project/monitor/nwpc-monitor-platform (master)
$ git merge -s ours --no-commit --allow-unrelated-histories hpc-model/master
Automatic merge went well; stopped before committing as requested
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 nwpc-monitor-platform 创建子项目的目录 nwpc-hpc-model。&lt;/p&gt;</description></item><item><title>添加索引提高MongoDB查询速度</title><link>https://blog.perillaroc.wang/post/2017/2017-06-27-add-index-to-speed-up-query-in-mongodb/</link><pubDate>Tue, 27 Jun 2017 16:39:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-06-27-add-index-to-speed-up-query-in-mongodb/</guid><description>&lt;p&gt;通过添加索引可以极大提高 MongoDB 的查询效率。&lt;/p&gt;
&lt;p&gt;在未添加检索时，查询某个条目需要进行全表搜索，从 &lt;code&gt;explain&lt;/code&gt; 的输出中可以看到，需要展开 2581 个文档，耗费 13630 微秒找到指定文档。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;executionStages&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;stage&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;COLLSCAN&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;filter&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;$and&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;$eq&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7821&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;owner&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;$eq&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;nwp_xp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;repo&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;$eq&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hpc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;nReturned&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;executionTimeMillisEstimate&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13630&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;works&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2583&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;advanced&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;needTime&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2581&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;needYield&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;saveState&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;527&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;restoreState&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;527&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;isEOF&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;invalidates&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;direction&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;forward&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;docsExamined&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2581&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们为 id 字段添加索引：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;blobs&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;createIndex&lt;/span&gt;({&lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;}, {&lt;span style="color:#a6e22e"&gt;unique&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再查找相同的文档，则会直接找到该文档。
从 explain 输出中可以看到，MongoDB 使用索引直接找到目标文档，用时为 0 毫秒。&lt;/p&gt;</description></item><item><title>制作网络小说的电子书</title><link>https://blog.perillaroc.wang/post/2017/2017-06-14-create-ebook-for-online-novel/</link><pubDate>Wed, 14 Jun 2017 12:57:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-06-14-create-ebook-for-online-novel/</guid><description>&lt;p&gt;最近一直在使用“追书神器”看小说，不过新版的“追书神器”不再提供免费网站，千万不要更新。
身为资深网络小说迷，怎能受制于人。&lt;/p&gt;
&lt;p&gt;另外，手机屏幕太小，阅读体验远比不上 Kindle 之类的电纸书。
是时候自己动手写个工具，将网络小说制成电子书，便于放到 Kindle 上阅读了。&lt;/p&gt;
&lt;h2 id="目标"&gt;目标&lt;/h2&gt;
&lt;p&gt;制作电子书需要下面几个步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;找到小说&lt;/li&gt;
&lt;li&gt;下载小说&lt;/li&gt;
&lt;li&gt;用下载的内容制作电子书&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当前只开发了下载小说的工具，支持从固定的网站下载小说。
而制作电子书则通过 calibre 软件实现。
下面就介绍下载小说的工具。&lt;/p&gt;
&lt;h2 id="下载小说"&gt;下载小说&lt;/h2&gt;
&lt;p&gt;下载小说分为两步：找目录、按目录下载每个章节。&lt;/p&gt;
&lt;p&gt;我使用 requests 获取网页，使用 beautiful soup 解析和输出 HTML 文件。&lt;/p&gt;
&lt;p&gt;目前仅针对&lt;a href="//www.wutuxs.com/"&gt;无图小说网&lt;/a&gt;开发下载工具。同样的思路也适用于其它小说网站。&lt;/p&gt;
&lt;h3 id="获取目录"&gt;获取目录&lt;/h3&gt;
&lt;p&gt;从小说目录页面获取目录链接列表，请看下面的函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_contents&lt;/span&gt;(url) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; list:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(url, proxies&lt;span style="color:#f92672"&gt;=&lt;/span&gt;proxies)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bs_object &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BeautifulSoup(response&lt;span style="color:#f92672"&gt;.&lt;/span&gt;content, &lt;span style="color:#e6db74"&gt;&amp;#34;html.parser&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_node &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bs_object&lt;span style="color:#f92672"&gt;.&lt;/span&gt;select(&lt;span style="color:#e6db74"&gt;&amp;#39;dd &amp;gt; table&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; link_nodes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; table_node[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;findAll(&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; contents &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a_link &lt;span style="color:#f92672"&gt;in&lt;/span&gt; link_nodes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;href&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; &lt;span style="color:#f92672"&gt;in&lt;/span&gt; a_link&lt;span style="color:#f92672"&gt;.&lt;/span&gt;attrs:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; href &lt;span style="color:#f92672"&gt;=&lt;/span&gt; a_link[&lt;span style="color:#e6db74"&gt;&amp;#39;href&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; link &lt;span style="color:#f92672"&gt;=&lt;/span&gt; urljoin(url, href)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; contents&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;: a_link&lt;span style="color:#f92672"&gt;.&lt;/span&gt;string,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;link&amp;#39;&lt;/span&gt;: link
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; contents
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="下载小说章节"&gt;下载小说章节&lt;/h3&gt;
&lt;p&gt;从每个章节页面获取章节内容，并组成新的HTML字符串，请看下面的函数。&lt;/p&gt;</description></item><item><title>在Electron中使用NeDB保存数据</title><link>https://blog.perillaroc.wang/post/2017/2017-06-03-using-nedb-to-store-data-in-electron/</link><pubDate>Sat, 03 Jun 2017 11:09:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-06-03-using-nedb-to-store-data-in-electron/</guid><description>&lt;p&gt;最近一个使用 Electron 构建的应用程序需要保存用户设置的数据，直接使用本地文件保存设置不容易操作，正好发现一些 JavaScript 实现的数据库，包括 PouchDB 和 NeDB 等。
Windows 下载 Electron 中使用 PouchDB 有问题，所以尝试使用 NeDB。&lt;/p&gt;
&lt;p&gt;NeDB 参照 MongoDB 设计，如果对 MongoDB 比较熟悉，上手很容易。下面只介绍简单的使用方法，详细文档请参考&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/louischatriot/nedb"&gt;https://github.com/louischatriot/nedb&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="创建数据库"&gt;创建数据库&lt;/h2&gt;
&lt;p&gt;NeDB 支持内存数据库或持久化数据库，应用程序中为了保存用户设置数据，选择以文件形式保存的持久化数据库。
下面的代码会在当前目录创建一个空的 data.db 文件，并自动加载数据库。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;const Datastore &lt;span style="color:#f92672"&gt;=&lt;/span&gt; require(&lt;span style="color:#e6db74"&gt;&amp;#39;nedb&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let data_db &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new Datastore({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename: &lt;span style="color:#e6db74"&gt;&amp;#39;data.db&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; autoload: true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;data_db&lt;/code&gt; 对象的内容如下：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wx2.sinaimg.cn/large/4afdac38ly1fg7tjiqum4j207d0733yi.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="插入文档"&gt;插入文档&lt;/h2&gt;
&lt;p&gt;类似 MongoDB，将数据表中的一个记录称为文档。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;doc&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;perillaroc&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data_db&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;insert&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;doc&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;new_doc&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;use strict&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;new_doc&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;回调函数中的变量如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wx2.sinaimg.cn/large/4afdac38ly1fg7tk18g6xj207q046wec.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;NeDB 会自动为每条文档添加唯一的 &lt;code&gt;_id&lt;/code&gt; 字段，文档会保存到数据文件 data.db 中，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;perillaroc&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;3wpPvbnmrrHvPhER&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;添加另外两个数据后，数据文件如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;perillaroc&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;3wpPvbnmrrHvPhER&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;lily&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;nesAU4EGnB98fb5C&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;lucy&amp;#34;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#34;_id&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;3jNUU4FH6RhG7es0&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="查询文档"&gt;查询文档&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;find&lt;/code&gt; 查找所有满足条件的文档，使用 &lt;code&gt;findOne&lt;/code&gt; 查找第一个满足条件的文档。&lt;/p&gt;</description></item><item><title>使用javascript后台下载图片</title><link>https://blog.perillaroc.wang/post/2017/2017-04-07-download-image-in-background-using-javascript/</link><pubDate>Fri, 07 Apr 2017 22:54:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-04-07-download-image-in-background-using-javascript/</guid><description>&lt;p&gt;设置 body 标签样式的 &lt;code&gt;background-image&lt;/code&gt; 属性，可以为 body 标签添加背景图片，代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;style&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;backgroundImage&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;url(some url)&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;浏览器会自动从 url 下载图片，并显示在界面上。
但如果网速不快时，界面上会看到图片逐渐加载的过程。为了避免浏览器显示图片下载过程，需要使用 javascript 在后台下载图片。&lt;br&gt;
通过 Image 类可以实现图片的后台下载。
Image 对象设置 src 属性后，浏览器就会在后台下载图片，无论该 Image 对象是否在 DOM 树中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let background_image &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new Image();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background_image&lt;span style="color:#f92672"&gt;.&lt;/span&gt;src &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;some url&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;图像下载是异步过程，当图片下载完成后，Image 对象会触发 load 事件。
我们可以在 load 事件的响应函数中将 body 的背景图片设为 Image 对象的图片。
注意，添加 load 事件处理函数一定要在设置 src 属性前。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;let background_image &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new Image();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background_image&lt;span style="color:#f92672"&gt;.&lt;/span&gt;onload &lt;span style="color:#f92672"&gt;=&lt;/span&gt; function(event){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document&lt;span style="color:#f92672"&gt;.&lt;/span&gt;body&lt;span style="color:#f92672"&gt;.&lt;/span&gt;style&lt;span style="color:#f92672"&gt;.&lt;/span&gt;backgroundImage &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;url(&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt; this&lt;span style="color:#f92672"&gt;.&lt;/span&gt;src &lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;)&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;background_image&lt;span style="color:#f92672"&gt;.&lt;/span&gt;src &lt;span style="color:#f92672"&gt;=&lt;/span&gt; image_url;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下载图片后切换背景图片，提高界面显示的流畅度。&lt;/p&gt;</description></item><item><title>使用Python进行中文词频统计</title><link>https://blog.perillaroc.wang/post/2017/2017-02-20-count-chinese-word-frequency-using-python/</link><pubDate>Mon, 20 Feb 2017 21:05:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-02-20-count-chinese-word-frequency-using-python/</guid><description>&lt;p&gt;最近在看《巨婴国》这本畅销书，先不论书写得怎么样，我就对书中的一个现象很感兴趣：谈论母亲远远多于谈论父亲。
正好可以学学如何使用 Python 进行中文词频统计。&lt;/p&gt;
&lt;h2 id="中文分词"&gt;中文分词&lt;/h2&gt;
&lt;p&gt;统计词频的首要任务就是分词。目前有很多中文分词的Python库，我选用jieba分词。&lt;br&gt;
使用方法极其简单，依次读取对文本文件的每一行并分词。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tokens &lt;span style="color:#f92672"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;join(os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;path&lt;span style="color:#f92672"&gt;.&lt;/span&gt;dirname(__file__), &lt;span style="color:#e6db74"&gt;&amp;#34;JuYingGuo.txt&amp;#34;&lt;/span&gt;)) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;readlines()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; line &lt;span style="color:#f92672"&gt;in&lt;/span&gt; lines:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clean_line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; len(clean_line) &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; seg_list &lt;span style="color:#f92672"&gt;=&lt;/span&gt; jieba&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cut(clean_line)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokens&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(seg)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意需要删除每行末尾的换行符，并过滤掉空行。&lt;br&gt;
分词结果如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wx2.sinaimg.cn/large/4afdac38ly1fcx7bv9z0zj20b40ajwem.jpg" alt=""&gt;&lt;/p&gt;
&lt;h2 id="词频统计"&gt;词频统计&lt;/h2&gt;
&lt;p&gt;分词得到的是整个文本的单词列表，统计词频需要统计每个词的个数。
Python 标准库 collection 提供的 &lt;code&gt;Counter&lt;/code&gt; 类可以很方便地统计个数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Counter(tokens)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以使用 &lt;code&gt;most_common&lt;/code&gt; 方法直接输出词频最高的5个单词&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; a &lt;span style="color:#f92672"&gt;in&lt;/span&gt; counter&lt;span style="color:#f92672"&gt;.&lt;/span&gt;most_common(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(a[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\t&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; str(a[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果如下表所示：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;单词&lt;/th&gt;
					&lt;th&gt;个数&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;，&lt;/td&gt;
					&lt;td&gt;21492&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;的&lt;/td&gt;
					&lt;td&gt;11396&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;。&lt;/td&gt;
					&lt;td&gt;7104&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;3682&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;我&lt;/td&gt;
					&lt;td&gt;2763&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;结果不尽如人意，最高频的竟然是标点符号，第二位的是助词，第五位是人称代词。
我对这类词语不感兴趣，只关心有实际意义的词语。所以需要对分词的结果进行处理。
这就需要使用停用表对结果进行过滤。&lt;/p&gt;
&lt;h2 id="停用表"&gt;停用表&lt;/h2&gt;
&lt;p&gt;停用表（stop words）就是那些“没有”实际意义的词，在词频统计时可以过滤掉。
有多家机构维护停用词表。
我在下面的 github 链接中找到几份停用词表，包括哈工大、百度、中科院、四川大学等四家机构的停用词表。&lt;/p&gt;</description></item><item><title>压缩HTTP请求正文</title><link>https://blog.perillaroc.wang/post/2017/2017-02-18-compress-http-request-body/</link><pubDate>Sat, 18 Feb 2017 23:24:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-02-18-compress-http-request-body/</guid><description>&lt;p&gt;当我们在 Web 服务器上启动 gzip 压缩后，会极大提高加载网页的速度。
同样，将 gzip 用于发送 HTTP 请求，也可以加快请求的响应速度。&lt;/p&gt;
&lt;h2 id="gzip库"&gt;gzip库&lt;/h2&gt;
&lt;p&gt;Python 内置标准库 gzip，像 GNU 程序 gzip 和 gunzip 一样提供文件压缩和解压缩功能。
Python 2 和 Python 3 的使用方法略有不同。&lt;/p&gt;
&lt;h3 id="python-2"&gt;Python 2&lt;/h3&gt;
&lt;p&gt;需要使用 &lt;code&gt;StringIO&lt;/code&gt; 模块的 &lt;code&gt;StringIO&lt;/code&gt; 类，创建 &lt;code&gt;StringIO&lt;/code&gt; 对象当做一个文件，传给 gzip 的 &lt;code&gt;GzipFile&lt;/code&gt; 对象，&lt;code&gt;GzipFile&lt;/code&gt; 会将字符串压缩后写入 &lt;code&gt;StringIO&lt;/code&gt; 对象。
使用 &lt;code&gt;getvalue&lt;/code&gt; 方法从 &lt;code&gt;StringIO&lt;/code&gt; 中获取压缩后的字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; StringIO&lt;span style="color:#f92672"&gt;.&lt;/span&gt;StringIO()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; gzip&lt;span style="color:#f92672"&gt;.&lt;/span&gt;GzipFile(fileobj&lt;span style="color:#f92672"&gt;=&lt;/span&gt;s, mode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;g&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(post_data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;g&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gzipped_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; s&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getvalue()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="python-3"&gt;Python 3&lt;/h3&gt;
&lt;p&gt;Python 3 的 gzip 库提供更方面的 &lt;code&gt;compress&lt;/code&gt; 和 &lt;code&gt;decompress&lt;/code&gt; 函数，可以直接压缩/解压缩字符串（bytes）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gzipped_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; gzip&lt;span style="color:#f92672"&gt;.&lt;/span&gt;compress(bytes(post_data), &lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解压缩&lt;/p&gt;</description></item><item><title>使用GSL实现二维数组插值</title><link>https://blog.perillaroc.wang/post/2017/2017-02-16-use-gsl-to-interpolate-2d-array/</link><pubDate>Thu, 16 Feb 2017 14:44:02 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-02-16-use-gsl-to-interpolate-2d-array/</guid><description>&lt;p&gt;当我们使用格点数据绘制填充图、等值线图时，就需要使用插值。
C++ 科学计算库 GSL 提供双线性插值算法，可以满足简单应用的需要。&lt;/p&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.gnu.org/software/gsl/"&gt;GSL&lt;/a&gt;（&lt;a href="https://www.gnu.org/software/gsl/"&gt;GNU Scientific Library&lt;/a&gt;）是由 GNU 出品的 C/C++ 数值计算开源库，由一系列数值计算程序组成，包括随机数生成器、线性代数、统计、插值等方面。&lt;/p&gt;
&lt;h2 id="二维数组插值"&gt;二维数组插值&lt;/h2&gt;
&lt;p&gt;给定一组递增的坐标 &lt;code&gt;x1,...,xm&lt;/code&gt;，和一组递增的坐标 &lt;code&gt;y1,...,yn&lt;/code&gt;，并给定每个二维网格点 &lt;code&gt;(xi,yi)&lt;/code&gt; 对应的数据 &lt;code&gt;z(i,j)&lt;/code&gt;。
二维数值插值就是一个连续的函数 &lt;code&gt;z(x,y)&lt;/code&gt;，满足 &lt;code&gt;z(xi,yi) = z(i,j)&lt;/code&gt;。如下图所示：&lt;/p&gt;
&lt;img class="alignnone" src="http://wx1.sinaimg.cn/large/4afdac38ly1fcs5sbxq5uj20iz0exdfx.jpg" alt="" width="683" height="537" /&gt; 
&lt;p&gt;已知 x 坐标 &lt;code&gt;x1,...,xm&lt;/code&gt; 和 y 坐标 &lt;code&gt;y1,...,yn&lt;/code&gt;，对应的 n * m 个点，通过插值求任意 x,y 坐标的数值。&lt;/p&gt;
&lt;h2 id="插值算法"&gt;插值算法&lt;/h2&gt;
&lt;p&gt;GSL二维数组插值支持两种插值算法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;双线性插值&lt;/li&gt;
&lt;li&gt;双三次插值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面简要介绍这两种插值算法：&lt;/p&gt;
&lt;h3 id="双线性插值"&gt;双线性插值&lt;/h3&gt;
&lt;p&gt;由最近的四个点进行两次线性插值得到结果，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wx3.sinaimg.cn/large/4afdac38ly1fcs7px1na9j20g30bo0t1.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;具体公式请参阅《&lt;a href="https://en.wikipedia.org/wiki/Bilinear_interpolation"&gt;Bilinear interpolation&lt;/a&gt;》&lt;/p&gt;
&lt;h3 id="双三次插值"&gt;双三次插值&lt;/h3&gt;
&lt;p&gt;由最近的十六个点插值得到结果，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src="http://wx4.sinaimg.cn/large/4afdac38ly1fcs7pwrrltj20c80ccgly.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;具体公式请参阅《&lt;a href="https://en.wikipedia.org/wiki/Bicubic_interpolation"&gt;Bicubic interpolation&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="gsl插值"&gt;GSL插值&lt;/h2&gt;
&lt;h3 id="已知数据"&gt;已知数据&lt;/h3&gt;
&lt;p&gt;x 坐标列表，x 坐标从小到大排列&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; x_coords
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;y 坐标列表，y 坐标从大到小排列&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; y_coords
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;格点数据，存放顺序为先 x 后 y。&lt;/p&gt;</description></item><item><title>为阿里云服务器WEB服务部署HTTPS协议</title><link>https://blog.perillaroc.wang/post/2017/2017-02-13-deploy-https-for-web-service-on-aliyun/</link><pubDate>Mon, 13 Feb 2017 21:19:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-02-13-deploy-https-for-web-service-on-aliyun/</guid><description>&lt;p&gt;随着人们对网络安全的重视，越来越多的网站启用 HTTPS 协议，并采用 HTTP 严格传输安全协议（HSTS）强制用户使用 HTTPS 协议访问网站。
尽管 HTTPS 协议加密解密需要占用 CPU 资源，但带来的安全收益远远大于资源的消耗。
所以，我也为自己开发一个为单位服务的外网网站部署 HTTPS 协议。&lt;/p&gt;
&lt;p&gt;网站托管于阿里云服务器上，并且绑定备案的域名。
阿里云提供证书服务（AliCloud Certificates Service），可以免费在云上签发Symantec证书，并提供一键部署云虚拟机的功能，大大简化证书部署。&lt;/p&gt;
&lt;p&gt;在证书服务页面购买证书后，需要在控制台证书界面补全证书的信息，包括域名、申请人信息等。证书界面还提供详细的安装说明，包括如何在 Nginx 等服务器上启动 HTTPS 协议。&lt;br&gt;
我的网站使用 Gunicorn 运行 Python Web 服务，用 Nginx 实现端口转发。配置方法与控制台给出的说明类似。
为实现 HTTP 自动转发到 HTTPS，需要作出一定的修改，使用如下配置：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;server {
 listen 80;
 server_name servername.com;
 return 301 https://www.servername.com$request_uri;
}
server {
 listen 443;
 ssl on;
 # 省略
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当用户访问 HTTP 网页时，会自动跳转到 HTTPS 网页，增强网页的安全性。&lt;/p&gt;
&lt;p&gt;后续将尝试部署 HSTS，提高首次访问的安全性。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.thoughtworks.com/radar/platforms/hsts"&gt;HSTS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.owasp.org/index.php/HTTP_Strict_Transport_Security"&gt;HTTP Strict Transport Security Cheat Sheet&lt;/a&gt;&lt;/p&gt;</description></item><item><title>MySQL中UTF-8文本无法识别的解决方法</title><link>https://blog.perillaroc.wang/post/2017/2017-02-12-solution-to-solve-utf-8-text-problem-in-mysql/</link><pubDate>Sun, 12 Feb 2017 14:20:22 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-02-12-solution-to-solve-utf-8-text-problem-in-mysql/</guid><description>&lt;p&gt;MySQL 中 &lt;code&gt;utf8_general_ci&lt;/code&gt; 使用 3 个字节表示 utf8 字符。但某些特殊的 utf8 字符需要占用 4 个字节，保存到 MySQL 中会发生如下错误：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sqlalchemy.exc.DatabaseError: (mysql.connector.errors.DatabaseError) 1366 (HY000): Incorrect string value: &amp;#39;\xF0\x9F\x8C\xB9\xE7\x8E...&amp;#39; for column &amp;#39;content&amp;#39; at row 1 ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL 5.5 及后续版本，添加对 4 位 utf8 字符的支持，需要将表格的编码方式改为 &lt;code&gt;utf8mb4&lt;/code&gt;，同时在执行SQL语句前，需要将服务器和客户端的编码也同样改为 &lt;code&gt;utf8mb4&lt;/code&gt;。
可以通过执行下面的 SQL 语句修改编码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SET&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NAMES&lt;/span&gt; utf8mb4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当使用 SQLAlchemy 时，连接数据库时将 &lt;code&gt;chartset&lt;/code&gt; 设为 utf8 即可，在执行数据操作前，先要执行上面的 SQL 语句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(&lt;span style="color:#e6db74"&gt;&amp;#39;SET NAMES utf8mb4&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就可以正常识别 UTF-8 字符了。&lt;/p&gt;</description></item><item><title>使用Requests下载文件</title><link>https://blog.perillaroc.wang/post/2017/2017-01-12-use-requests-to-download-file/</link><pubDate>Thu, 12 Jan 2017 21:35:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2017/2017-01-12-use-requests-to-download-file/</guid><description>&lt;p&gt;urllib 模块 (python2.7，python3 改为 urllib.request) 提供 &lt;code&gt;urlretrieve&lt;/code&gt; 函数下载文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;urlretrieve(url, download_path)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码从 url 下载文件保存到本地，本地文件路径为 &lt;code&gt;download_path&lt;/code&gt;。
不过，该函数在 python 3.6 版本中已不再推荐使用，后续可能会被移除。&lt;/p&gt;
&lt;p&gt;urllib 和 urllib2 接近底层，比较难用，Requests 库封装复杂的借口，提供更人性化的 HTTP 客户端，但不直接提供下载文件的函数。
需要通过为请求设置特殊参数 &lt;code&gt;stream&lt;/code&gt; 来实现。当 &lt;code&gt;stream&lt;/code&gt; 设为 &lt;code&gt;True&lt;/code&gt; 时，上述请求只下载 HTTP 响应头，并保持连接处于打开状态，直到访问 &lt;code&gt;Response.content&lt;/code&gt; 属性时才开始下载响应主体内容。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(url, stream&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码运行后，响应头 &lt;code&gt;r.headers&lt;/code&gt; 已下载，连接保持打开状态，允许我们进一步控制。
可以使用 &lt;code&gt;Response.iter_content()&lt;/code&gt;, &lt;code&gt;Response.iter_lines()&lt;/code&gt; 方法控制，或者使用 &lt;code&gt;Response.raw&lt;/code&gt;读取原始数据。&lt;/p&gt;
&lt;p&gt;下面介绍使用 &lt;code&gt;iter_content&lt;/code&gt; 和 &lt;code&gt;raw&lt;/code&gt; 下载文件的方法。&lt;/p&gt;
&lt;h2 id="iter_content"&gt;iter_content&lt;/h2&gt;
&lt;p&gt;请看下面的函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;download_file&lt;/span&gt;(url, download_path):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(url, stream&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; r&lt;span style="color:#f92672"&gt;.&lt;/span&gt;status_code &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(download_path, &lt;span style="color:#e6db74"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; chunk &lt;span style="color:#f92672"&gt;in&lt;/span&gt; r&lt;span style="color:#f92672"&gt;.&lt;/span&gt;iter_content(chunk_size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;write(chunk)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述函数每次读取 1024 字节（1KB）数据，写入到文件中。
&lt;code&gt;chunk_size&lt;/code&gt; 默认为 1，可以设为任意整数或 None（每次接收到的块大小）。&lt;/p&gt;</description></item><item><title>多进程运行grib2micaps程序</title><link>https://blog.perillaroc.wang/post/2016/2016-11-28-e5a49ae8bf9be7a88be8bf90e8a18cgrib2micapse7a88be5ba8f/</link><pubDate>Mon, 28 Nov 2016 18:22:42 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-11-28-e5a49ae8bf9be7a88be8bf90e8a18cgrib2micapse7a88be5ba8f/</guid><description/></item><item><title>使用Moment.js处理日期</title><link>https://blog.perillaroc.wang/post/2016/2016-11-25-e4bdbfe794a8moment-jse5a484e79086e697a5e69c9f/</link><pubDate>Fri, 25 Nov 2016 14:42:10 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-11-25-e4bdbfe794a8moment-jse5a484e79086e697a5e69c9f/</guid><description/></item><item><title>彻底删除Git中的文件</title><link>https://blog.perillaroc.wang/post/2016/2016-11-10-e5bdbbe5ba95e588a0e999a4gite4b8ade79a84e69687e4bbb6/</link><pubDate>Thu, 10 Nov 2016 10:29:40 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-11-10-e5bdbbe5ba95e588a0e999a4gite4b8ade79a84e69687e4bbb6/</guid><description/></item><item><title>使用git subtree管理子项目</title><link>https://blog.perillaroc.wang/post/2016/2016-09-27-use-git-subtree-to-manage-sub-project/</link><pubDate>Tue, 27 Sep 2016 15:20:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-09-27-use-git-subtree-to-manage-sub-project/</guid><description>&lt;blockquote&gt;
&lt;p&gt;已有更新版本，请参看《&lt;a href="https://blog.perillaroc.wang/post/2016/2016-09-27-use-git-subtree-to-manage-sub-project/"&gt;使用git subtree管理子项目 v2&lt;/a&gt;》&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;某个项目同时被多个项目使用，并且该项目也同时在开发，就需要在一个git项目（比如web-A）中嵌入另一个git项目（lib-B），并有如下的需求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;项目 web-A 中某个子目录内容与项目 lib-B，可以获取 lib-B 的更新，合并到项目 web-A 中。&lt;/li&gt;
&lt;li&gt;可以在项目 web-A 中编辑项目 lib-B 的文件，并将该改动推送到项目 lib-B 中。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用 git subtree 可以实现上述功能。&lt;br&gt;
下面在 nwpc-monitor-platform 项目中添加子项目 nwpc-work-flow-model。&lt;/p&gt;
&lt;h1 id="建立关联"&gt;建立关联&lt;/h1&gt;
&lt;p&gt;在 nwpc-monitor-platform 中添加 nwpc-work-flow-model 为远程分支。&lt;/p&gt;
&lt;pre&gt;$ git remote add -f nwpc-work-flow-model git@github.com:perillaroc/nwpc-work-flow-model.git
Updating nwpc-work-flow-model
warning: no common commits
remote: Counting objects: 135, done.
remote: Compressing objects: 100% (69/69), done.
Receiving objects: 53% (72/135)remote: Total 135 (delta 66), reused 132 (delta 63), pack-reused 0
Receiving objects: 100% (135/135), 26.91 KiB | 0 bytes/s, done.
Resolving deltas: 100% (66/66), done.
From github.com:perillaroc/nwpc-work-flow-model
 * [new branch] master -&gt; nwpc-work-flow-model/master&lt;/pre&gt;
&lt;p&gt;在 nwpc-monitor-platform 创建子项目的目录 nwpc_work_flow_model&lt;/p&gt;</description></item><item><title>WEB API中使用Google Analytics</title><link>https://blog.perillaroc.wang/post/2016/2016-09-27-web-apie4b8ade4bdbfe794a8google-analytics/</link><pubDate>Tue, 27 Sep 2016 14:45:07 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-09-27-web-apie4b8ade4bdbfe794a8google-analytics/</guid><description/></item><item><title>为现有Git项目中的子目录建立新项目</title><link>https://blog.perillaroc.wang/post/2016/2016-09-27-e4b8bae78eb0e69c89gite9a1b9e79baee4b8ade79a84e5ad90e79baee5bd95e5bbbae7ab8be696b0e9a1b9e79bae/</link><pubDate>Tue, 27 Sep 2016 13:40:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-09-27-e4b8bae78eb0e69c89gite9a1b9e79baee4b8ade79a84e5ad90e79baee5bd95e5bbbae7ab8be696b0e9a1b9e79bae/</guid><description/></item><item><title>AIX下编译Python</title><link>https://blog.perillaroc.wang/post/2016/2016-09-22-build-python-on-aix/</link><pubDate>Thu, 22 Sep 2016 14:48:30 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-09-22-build-python-on-aix/</guid><description>&lt;p&gt;AIX 上安装的 Python 版本为 2.5.2，缺少 Python 2.7 版本添加的诸多新功能，也无法尝试 Python 3.X 版本全新的特性。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cma20n03:/cma/u/nwp/bin $ python -V
Python 2.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;好在我们可以手动编译。&lt;/p&gt;
&lt;h1 id="编译-python-2"&gt;编译 Python 2&lt;/h1&gt;
&lt;p&gt;版本：&lt;a href="https://www.python.org/downloads/release/python-2712/"&gt;Python 2.7.12&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;运行下面的 configure 命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;YOUR_INSTALL_DIR --disable-ipv6 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --with-libs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;-L/opt/freeware/lib --disable-shared --without-computed-gotos &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlc CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进行编译：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行测试：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会发现如下错误：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;./python -Wd -3 -E -tt ./Lib/test/regrtest.py -l
Traceback (most recent call last):
 File &amp;#34;./Lib/test/regrtest.py&amp;#34;, line 230, in &amp;amp;lt;module&amp;gt;
 TEMPDIR = os.path.abspath(tempfile.gettempdir())
 File &amp;#34;...省略.../Python-2.7.12/Lib/tempfile.py&amp;#34;, line 274, in gettempdir
 tempdir = _get_default_tempdir()
 File &amp;#34;...省略.../Python-2.7.12/Lib/tempfile.py&amp;#34;, line 196, in _get_default_tempdir
 fd = _os.open(filename, flags, 0o600)
OverflowError: signed integer is greater than maximum
make: The error code from the last command is 1.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;查看源文件后，发现该错误因变量 flags 过大导致。&lt;/p&gt;</description></item><item><title>小内存虚拟机中使用MongoDB数据库</title><link>https://blog.perillaroc.wang/post/2016/2016-07-29-e5b08fe58685e5ad98e8999ae68b9fe69cbae4b8ade4bdbfe794a8mongodbe695b0e68daee5ba93/</link><pubDate>Fri, 29 Jul 2016 16:49:44 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-07-29-e5b08fe58685e5ad98e8999ae68b9fe69cbae4b8ade4bdbfe794a8mongodbe695b0e68daee5ba93/</guid><description/></item><item><title>Kafka应用：批量接收消息保存到MySQL中</title><link>https://blog.perillaroc.wang/post/2016/2016-07-19-kafkae5ba94e794a8efbc9ae689b9e9878fe68ea5e694b6e6b688e681afe4bf9de5ad98e588b0mysqle4b8ad/</link><pubDate>Tue, 19 Jul 2016 13:55:44 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-07-19-kafkae5ba94e794a8efbc9ae689b9e9878fe68ea5e694b6e6b688e681afe4bf9de5ad98e588b0mysqle4b8ad/</guid><description/></item><item><title>Python中的Kafka：使用kafka-python库</title><link>https://blog.perillaroc.wang/post/2016/2016-07-12-pythone4b8ade79a84kafkaefbc9ae4bdbfe794a8kafka-pythone5ba93/</link><pubDate>Tue, 12 Jul 2016 12:33:03 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-07-12-pythone4b8ade79a84kafkaefbc9ae4bdbfe794a8kafka-pythone5ba93/</guid><description/></item><item><title>CentOS中使用SOCKS代理安装软件</title><link>https://blog.perillaroc.wang/post/2016/2016-07-11-centose4b8ade4bdbfe794a8sockse4bba3e79086e5ae89e8a385e8bdafe4bbb6/</link><pubDate>Mon, 11 Jul 2016 22:43:59 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-07-11-centose4b8ade4bdbfe794a8sockse4bba3e79086e5ae89e8a385e8bdafe4bbb6/</guid><description/></item><item><title>使用MySQL生成自增主键</title><link>https://blog.perillaroc.wang/post/2016/2016-06-13-e4bdbfe794a8mysqle7949fe68890e887aae5a29ee4b8bbe994ae/</link><pubDate>Mon, 13 Jun 2016 09:27:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-06-13-e4bdbfe794a8mysqle7949fe68890e887aae5a29ee4b8bbe994ae/</guid><description/></item><item><title>Flask中添加自定义转换器(Converter)</title><link>https://blog.perillaroc.wang/post/2016/2016-06-05-create-converter-in-flask/</link><pubDate>Sun, 05 Jun 2016 21:09:45 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-06-05-create-converter-in-flask/</guid><description>&lt;p&gt;Flask 提供的测试服务器对静态文件支持不佳，解析网页的路由与静态文件的路径冲突。
在生产环境中，使用 Ngnix 等服务器都支持静态文件，所以可以用生产环境的静态文件 url 代替开发环境的 url。&lt;br&gt;
或者，可以为静态文件配置单独的控制器，使用 &lt;code&gt;send_from_directory&lt;/code&gt; 等函数返回文件。&lt;br&gt;
我尝试使用下面的两个路由设置，没成功。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@app.route&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/static/&amp;lt;path:path&amp;gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@app.route&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;lt;owner&amp;gt;/&amp;lt;repo&amp;gt;/&amp;lt;path:path&amp;gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解析 &lt;code&gt;/static/app/index.js&lt;/code&gt; 文件失败，使用第二个路由（位置问题？有时间再试）。&lt;br&gt;
Stackoverflow 上的一个回答给出几种解决方法，其中一种方法使用自定义的转换器（Converter）来设置路由匹配。&lt;/p&gt;
&lt;h2 id="converter"&gt;Converter&lt;/h2&gt;
&lt;p&gt;转换器对路由路径中参数进行限定，比如 &lt;code&gt;int&lt;/code&gt; 表示接受 int 型的路径参数，上面的路由中的 &lt;code&gt;path&lt;/code&gt; 也是一种转换器，接受包括斜杠 (&lt;code&gt;/&lt;/code&gt;) 的字符串，通常用于路由匹配表达式的最后。&lt;br&gt;
Flask 的转换器 (Converter) 来自 werkzeug 库，该库还提供自定义转换器的功能。
下面我就利用自定义一个转换器来区分静态文件和非静态文件。&lt;/p&gt;
&lt;h2 id="converter-说明"&gt;Converter 说明&lt;/h2&gt;
&lt;p&gt;下面是一个来自 werkzeug 库的自定义 Converter 实例。&lt;a href="//werkzeug.pocoo.org/docs/0.11/routing/#custom-converters"&gt;网址&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; random &lt;span style="color:#f92672"&gt;import&lt;/span&gt; randrange
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; werkzeug.routing &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Rule, Map, BaseConverter, ValidationError
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BooleanConverter&lt;/span&gt;(BaseConverter):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, url_map, randomify&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; super(BooleanConverter, self)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(url_map)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;randomify &lt;span style="color:#f92672"&gt;=&lt;/span&gt; randomify
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;regex &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;(?:yes|no|maybe)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_python&lt;/span&gt;(self, value):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; value &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;maybe&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;randomify:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; randrange(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; ValidationError()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; value &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;yes&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to_url&lt;/span&gt;(self, value):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; value &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;yes&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;or&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;no&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;自定义的 Converter 需要至少定义两个方法：&lt;code&gt;to_python&lt;/code&gt; 和 &lt;code&gt;to_url&lt;/code&gt;。&lt;br&gt;
&lt;code&gt;to_python&lt;/code&gt; 用于将 URL 中的路径转换为 Python 对象，传递给 view 函数。&lt;br&gt;
&lt;code&gt;to_url&lt;/code&gt; 则由 &lt;code&gt;url_for&lt;/code&gt; 调用，将参数转换为 URL 中合适的形式。&lt;/p&gt;</description></item><item><title>Pycharm5注册方式</title><link>https://blog.perillaroc.wang/post/2016/2016-05-30-pycharm-license-server/</link><pubDate>Mon, 30 May 2016 14:29:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-05-30-pycharm-license-server/</guid><description>&lt;blockquote&gt;
&lt;p&gt;注：本文方法已不可用，请支持正版&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在注册时选择 License server ，填 //15.idea.lanyus.com/，然后点击 OK。&lt;/p&gt;</description></item><item><title>CentOS 7安装Redis</title><link>https://blog.perillaroc.wang/post/2016/2016-05-19-install-redis-in-centos-7/</link><pubDate>Thu, 19 May 2016 10:02:33 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-05-19-install-redis-in-centos-7/</guid><description>&lt;p&gt;CentOS 的默认源中没有 Redis 等软件包，可以使用 fedora 项目组的 EPEL 源（企业版 LInux 附件软件包）。&lt;br&gt;
使用&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install epel-release
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装 EPEL 源，或者使用如下方式安装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;wget -r --no-parent -A &lt;span style="color:#e6db74"&gt;&amp;#39;epel-release-*.rpm&amp;#39;&lt;/span&gt; //dl.fedoraproject.org/pub/epel/7/x86_64/e/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-*.rpm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来就可以使用&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install redis
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装 Redis 软件包。&lt;/p&gt;
&lt;h2 id="参考"&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://fedoraproject.org/wiki/EPEL/zh-cn"&gt;https://fedoraproject.org/wiki/EPEL/zh-cn&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.5.3 —— Back Archiving</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-3-back-archiving/</link><pubDate>Fri, 26 Feb 2016 11:24:28 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-3-back-archiving/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*该例子只运行一次。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="说明"&gt;说明&lt;/h2&gt;
&lt;p&gt;某个旧归档系统中有从 1990-01-01 到 1995-07-12 的数据。&lt;br&gt;
这些数据需要拷贝到新的归档系统中。&lt;br&gt;
在写入新归档系统前需要处理数据。&lt;br&gt;
数据可以被单独拷贝。&lt;br&gt;
旧归档系统中的数据按日期组织。系统应该拷贝一天的数据。&lt;br&gt;
同一时刻只有两个任务能访问旧归档系统。&lt;/p&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;编写 suite definition&lt;/li&gt;
&lt;li&gt;设计 suite，使新的数据类型可以方便地添加其中。&lt;br&gt;
有用的提示：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Limits#limits"&gt;Limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Limits#inlimit"&gt;inlimit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+variables#add-variable"&gt;ecFlow variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Add+Trigger#add-trigger"&gt;Add Trigger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Repeat#repeat"&gt;Repeat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Using+python+scripting#using-python-scripting"&gt;Using python scripting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+Python+Api#suite-definition-python-api"&gt;Suite Definition API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考答案《&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Back+archiving+solution#back-archiving-soln"&gt;Back archiving solution&lt;/a&gt;》&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.5.2 —— 业务 Suite（Operation Suite）</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-2-e4b89ae58aa1-suiteefbc88operation-suiteefbc89/</link><pubDate>Fri, 26 Feb 2016 11:20:11 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-2-e4b89ae58aa1-suiteefbc88operation-suiteefbc89/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*业务 suite 包含两个循环，00 和 12.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个循环包括三个部分；&lt;br&gt;
分析&lt;/p&gt;&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 获取观测资料
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 运行分析模式
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 后处理数据
&lt;/p&gt;
&lt;p&gt;预报&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 准备输入数据
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 运行预报模式。预报模式每6小时输出数据，00 循环输出24小时，12 循环输出 240 小时。
&lt;/p&gt;
&lt;p&gt;归档&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 保存分析结果
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 当可用时，保存预报结果
&lt;/p&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;编写 suite definition&lt;/li&gt;
&lt;li&gt;ecf script 该如何组织&lt;br&gt;
有用的提示&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Add+Trigger#add-trigger"&gt;Add Trigger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Add+a+meter#add-meter"&gt;Add a meter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+variables#add-variable"&gt;ecFlow variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Using+python+scripting#using-python-scripting"&gt;Using python scripting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/File+location#file-location"&gt;File location&lt;/a&gt; for ECF_FILES&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+Python+Api#suite-definition-python-api"&gt;Suite Definition API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考答案《&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Operational+Suite+Solution#operational-suite-soln"&gt;Operational Suite Solution&lt;/a&gt;》&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.5.1 —— 数据获取</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-1-e695b0e68daee88eb7e58f96/</link><pubDate>Fri, 26 Feb 2016 11:15:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-1-e695b0e68daee88eb7e58f96/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="要求"&gt;要求&lt;/h2&gt;
&lt;p&gt;每小时，从 Exeter，Toulouse 和 Offenbach 接收数据。&lt;br&gt;
每三小时，从 Washington 接收数据&lt;br&gt;
每天，从 Tokeyo 接收数据&lt;br&gt;
每周一，从 Melbourne 接收数据&lt;br&gt;
每月第一天，从 Montreal 接收数据&lt;br&gt;
接收的数据种类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;观测&lt;/li&gt;
&lt;li&gt;GRIB 场&lt;/li&gt;
&lt;li&gt;卫星图片&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接收数据需要三个步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从外部接收数据&lt;/li&gt;
&lt;li&gt;处理数据&lt;/li&gt;
&lt;li&gt;将数据保存到数据库中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每天从数据库中检索前一天接收的数据并写入归档文件。&lt;/p&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;编写 suite 的 suite definition&lt;br&gt;
有用的参考：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Add+Trigger#add-trigger"&gt;Add Trigger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Dates+and+Clocks#dates-and-clocks"&gt;Dates and Clocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;time&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Time+Dependencies#date-or-day"&gt;date or day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Repeat#repeat"&gt;Repeat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+Python+Api#suite-definition-python-api"&gt;Suite Definhition API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为没有标准 unix 日期操作命令，可以使用 ecf_date。&lt;br&gt;
参考答案《&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Data+acquisition+solution#data-acquisition-soln"&gt;Data acquisition solution&lt;/a&gt;》&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.5 —— 练习</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-e7bb83e4b9a0/</link><pubDate>Fri, 26 Feb 2016 11:10:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-5-e7bb83e4b9a0/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*下面的课程，我们将尝试设计一个真正的 suite。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从提供的三个练习中选择一个，并尝试为其设计 suite definition。如果有时间，用空白 ecf script 实现整个 suite，脚本中简单地在完成前 sleep 几秒钟。&lt;/p&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.9 —— Zombie</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-9-zombie/</link><pubDate>Fri, 26 Feb 2016 11:01:45 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-9-zombie/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*Zombie 是与 ecflow_server 通信验证权限失败的正在运行的作业。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="如何产生"&gt;如何产生&lt;/h2&gt;
&lt;p&gt;多种原因，常见的集中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;作业运行时，节点树被删除、替换、重新加载。&lt;/li&gt;
&lt;li&gt;作业正在运行时（处于 submitted 或 active 状态），被重新运行&lt;/li&gt;
&lt;li&gt;作业被强制设为新状态，如 complete&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更罕见的原因有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ecf 脚本错误，多次运行初始化或完成命令&lt;/li&gt;
&lt;li&gt;ecf script 中的 child command 被放到后台，这种情况下，子节点命令执行顺序不正确。&lt;/li&gt;
&lt;li&gt;负载控制器多次提交作业&lt;/li&gt;
&lt;li&gt;服务器宕机，恢复 check point 文件过期&lt;/li&gt;
&lt;li&gt;机器故障&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="如何处理"&gt;如何处理&lt;/h2&gt;
&lt;p&gt;init complete wait 命令的默认行为是 block 作业，event label meter的默认行为是 fob。&lt;br&gt;
子节点命令持续尝试连接 ecflow_server，直到24小时（由 ecflow_client 端的 ECF_TIMEOUT 指定）。&lt;br&gt;
可以设置子节点命令在服务器拒绝连接时立刻出错（查看 ecflow_client 的 ECF_DENIED）。&lt;br&gt;
ecflowview 提供一个对话框，列出所有的 zombies 和可以采用的处理方法。包括：&lt;br&gt;
&lt;strong&gt;Terminate&lt;/strong&gt;&lt;br&gt;
令命令失败，根据脚本可能会调用 abort 命令，会导致生成新的 zombie。&lt;br&gt;
&lt;strong&gt;Fob&lt;/strong&gt;&lt;br&gt;
允许作业继续运行。child command 命令运行结束，因此不再阻止作业。&lt;br&gt;
但要特别注意可能会出现的问题。如果有两个运行中的作业，会导致数据冲突。即便有大哥作业，可以能产生问题。例如，相关命令是 event 命令，该 event 将不会被设置，如果后续的 trigger 表达式中有该 event，该 trigger 就不会生效。&lt;br&gt;
&lt;strong&gt;Delete&lt;/strong&gt;&lt;br&gt;
从服务器移除 zombie，作业仍被阻塞，子节点命令再次尝试连接 ecflow_server 时，会再次出现zombie。&lt;br&gt;
手动杀掉作业时，可以使用该选项&lt;br&gt;
&lt;strong&gt;Rescure&lt;/strong&gt;&lt;br&gt;
接受 zombie，更新节点树。zobmie 的 ECF_PASS 将会拷贝到 task 上，因此下一次的 child command 将会正常运行。用户要确保没有其他作业运行。&lt;br&gt;
&lt;strong&gt;Kill&lt;/strong&gt;&lt;br&gt;
使用 ECF_KILL_CMD 杀掉 zombie。如果脚本中正确的信号捕获，该操作会以调用 abort 结束。&lt;br&gt;
path zombies 需要手动杀掉。&lt;br&gt;
注意：上面四中方法中，只有 Rescue 允许 child command 修改节点树的状态。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.8 —— 面向对象 suite</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-8-e99da2e59091e5afb9e8b1a1-suite/</link><pubDate>Fri, 26 Feb 2016 10:49:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-8-e99da2e59091e5afb9e8b1a1-suite/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;*Python 的面向对象设计特性允许我们在设计和构建 suite definition 时考虑灵活性。设计每个 suite 有不同的准则。让我们考虑如何以一种更面向对象的方式设计本教程的例子。我们以一些设计准则开始。&lt;/p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;默认变量必须设置，并与 suite 独立&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新的 suite 必须开启自动检测 job 生成。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要将 definition 保存到单独的文件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新的 suite 应该能够复用为上面要求而设计的代码&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面是一种可行的设计，使用单例模式和模板模式。&lt;/p&gt;
&lt;pre class="lang:py"&gt;#!/usr/bin/env python2.7
import os
import ecflow
class DefaultVariables(object):
 """Provide the setup variables for each suite"""
 def add_to(self, node):
 """Adds ECF_INCLUDE,ECF_HOME to the input node"""
 node.add_variable("ECF_INCLUDE", os.path.join(os.getenv("HOME"), "course"))
 node.add_variable("ECF_HOME", os.path.join(os.getenv("HOME"), "course"))
class BaseSuiteBuilder(object):
 """Abstract class. Add default variables to suite and enable job creation
 checking for any derived suite
 """
 def __init__(self, default_variables):
 self.defs = ecflow.Defs()
 # use derived class name as suite name
 self.suite = self.defs.add_suite(type(self).__name__)
 default_variables.add_to(self.suite)
 def _build_definition_hook(self):
 """Derived suite should override this function to build the suite
 Should not be called explicitly. How could we enforce this ?
 """
 pass
 def setup(self):
 """Template/skeleton function.
 Provides common algorithm for *all* derivatives
 Uses Hollywood principle.
 """
 # Build the suite
 self._build_definition_hook()
 # check job creation. Could use an assert
 job_check_result = self.defs.check_job_creation()
 if len(job_check_result) != 0:
 print "Job creation failed\n" + job_check_result
 # Check trigger expressions and limit references"
 print self.defs.check()
 # Allows definition creation to be separated from the load
 # Use the class name as the name of the definition file
 self.defs.save_as_defs( type(self).__name__ + ".def")
class SuiteBuilder(BaseSuiteBuilder):
 """My example suite. Generates SuiteBuilder.def"""
 def __init__(self, default_variables):
 BaseSuiteBuilder.__init__(self, default_variables)
 def _build_definition_hook(self):
 f1 = self.suite.add_family("family")
 f1.add_task("task1")
 f1.add_task("task2")
class TestSuite(BaseSuiteBuilder):
 """My test suite. Generates TestSuite.def"""
 def __init__(self, default_variables):
 BaseSuiteBuilder.__init__(self, default_variables)
 def _build_definition_hook(self):
 self.suite.add_task("task1")
if __name__ == "__main__":
 my_suite = SuiteBuilder(DefaultVariables())
 my_suite.setup()
 my_test_suite = TestSuite(DefaultVariables())
 my_test_suite.setup()&lt;/pre&gt;
&lt;h2 id="词汇表"&gt;词汇表&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-suite-definition"&gt;suite definition&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.7 —— 使用 python 脚本</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-7-e4bdbfe794a8-python-e8849ae69cac/</link><pubDate>Fri, 26 Feb 2016 10:47:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-7-e4bdbfe794a8-python-e8849ae69cac/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*以前已经看到，ecFlow 有 ecFlow Python Api：&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="lang:py"&gt;#!/usr/bin/env python2.7
import ecflow&lt;/pre&gt;
&lt;p&gt;允许我们使用 python 构建 suite definition，也可以使用 python 与 ecflow_server 通讯。&lt;br&gt;
这是个强大的功能，可以帮助我们以相对简化的方式定义复杂的 suite。&lt;br&gt;
考虑下面的 suite：&lt;/p&gt;
&lt;pre&gt;suite test
 family f1
 task a
 task b
 task c
 task d
 task e
 endfamily
 family f2
 task a
 task b
 task c
 task d
 task e
 endfamily
 family f3
 task a
 task b
 task c
 task d
 task e
 endfamily
 family f4
 task a
 task b
 task c
 task d
 task e
 endfamily
 family f5
 task a
 task b
 task c
 task d
 task e
 endfamily
 family f6
 task a
 task b
 task c
 task d
 task e
 endfamily
endsuite&lt;/pre&gt;
&lt;p&gt;用 python 可以写成：&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.6 —— 日期和时钟</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-6-e697a5e69c9fe5928ce697b6e9929f/</link><pubDate>Fri, 26 Feb 2016 10:42:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-6-e697a5e69c9fe5928ce697b6e9929f/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*因为 ecFlow 是为 ECMWF 系统设计的，所以日期是一个重要的概念。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 clock 定义 suite 的日期，clock 是 suite 的树形，不同的 suite 可以有不同的时钟。&lt;br&gt;
两种类型&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;real clock：真实的机器时间，日期在零点或增加一天&lt;/li&gt;
&lt;li&gt;hybrid clock：日期和时间不相关，在 suite 完成前，日期固定，主要适用于超过24小时的 suite。时间与机器时间相同&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;suite 的 clock 可以修改。这对那些运行在过去日期的 suite 十分有用（例如清除旧数据）&lt;br&gt;
ECF_DATE：生成变量，日期&lt;br&gt;
ECF_TIME：生成变量，时间&lt;br&gt;
ECF_CLOCK：生成变量，更详细的信息，例如星期&lt;br&gt;
&lt;img class="alignnone" src="http://ww4.sinaimg.cn/mw690/4afdac38jw1f1cjfdj9e9j20bn07wmxz.jpg" alt="" width="419" height="284" /&gt;&lt;br&gt;
job 中使用 suite 生成的日期和时间变量更安全，不推荐直接访问系统时间。&lt;/p&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;尝试修改 suite，使用 {shell}ecflow_client –alter{/shell} 用上一周的某个 clock 日期运行 suite。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ ecflow_client --alter change clock_date 10.02.2016 /test&lt;/pre&gt;
&lt;ol start="2"&gt;
&lt;li&gt;查看 ecFlow 的变量。&lt;br&gt;
&lt;img class="alignnone" src="http://ww3.sinaimg.cn/large/4afdac38jw1f1cjfdsva9j20bp07xwfc.jpg" alt="" width="421" height="285" /&gt;&lt;br&gt;
注意：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如果使用 repeat date 类型结构，date、day和 clock 属性当前不可用。&lt;/li&gt;
&lt;li&gt;带单个时间依赖的 cron 会自动重新提交。&lt;/li&gt;
&lt;li&gt;修改时钟后，需要重新排队整个 suite。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="词汇表"&gt;词汇表&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-clock"&gt;clock&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-suite"&gt;suite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-real-clock"&gt;real clock&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-hybrid-clock"&gt;hybrid clock&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-variable"&gt;variable&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecflow-client"&gt;ecflow_client&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-date"&gt;date&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-day"&gt;day&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-repeat"&gt;repeat&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-cron"&gt;cron&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.5 —— 文件位置</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-5-e69687e4bbb6e4bd8de7bdae/</link><pubDate>Fri, 26 Feb 2016 10:36:24 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-5-e69687e4bbb6e4bd8de7bdae/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*目前位置，我们看到 ecflow_server 在特定的位置寻找需要的文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用如下变量控制寻找文件的位置：&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ECF_INCLUDE：include 文件&lt;/li&gt;
&lt;li&gt;ECF_FILES：如果 ecf 脚本没在默认位置，则 ecflow_server 在该位置寻找ecf脚本&lt;/li&gt;
&lt;li&gt;ECF_OUT：作业输出文件位置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果两个 task 使用相同的 ecf script，区别只是简单地位某个变量设置不同的值，那我们不需要维护多个相同文件的拷贝。可以在 suite 中的不同位置用同一个名称使用同一个脚本，将该脚本放在公用目录下，并将变量 ECF_FILES 设为该位置。&lt;br&gt;
许多用户只是用一个目录，并将 ECF_FILES 指向该目录。&lt;br&gt;
如果 task 有不同名字，可以使用 unix 命令 {shell}ln -s{/shell} 创建链接。&lt;br&gt;
总结下：&lt;br&gt;
不同作业有相同名字，使用同一个文件&lt;br&gt;
不同作业有不同名字，链接到同一个文件&lt;/p&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;p&gt;想象在我们的示例 suite 中如何使用 ECF_FILES 和 ln 来减少脚本数目。&lt;br&gt;
windroc：测试使用 ECF_FILES 和 ln&lt;/p&gt;
&lt;h2 id="词汇表"&gt;词汇表&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecflow-server"&gt;ecflow_server&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-variable"&gt;variable&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecf-script"&gt;ecf script&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-suite"&gt;suite&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.4 —— 运行远程作业</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-4-e8bf90e8a18ce8bf9ce7a88be4bd9ce4b89a/</link><pubDate>Fri, 26 Feb 2016 10:33:18 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-4-e8bf90e8a18ce8bf9ce7a88be4bd9ce4b89a/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*ecFlow 使用 ECF_JOB_CMD 变量值提交作业。修改该变量可以控制在哪里如何运行作业。该变量应该与 ECF_JOB 和 ECF_JOBOUT变量同时使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ECF_JOB 是作业文件的路径&lt;br&gt;
ECF_JOBOUT 是标准输出流的文件位置&lt;br&gt;
默认的命令&lt;/p&gt;&lt;/p&gt;
&lt;pre&gt;ECF_JOB_CMD = %ECF_JOB% 1&amp;gt; %ECF_JOBOUT% 2&amp;gt;&amp;1 &amp;&lt;/pre&gt;
&lt;p&gt;接下来，我们将在远程主机上运行程序。需要使用 UNIX 命令 ssh。&lt;br&gt;
我们喜欢使用 HOST 变量定义远程主机的名字，我们假设所有远程主机上的文件都可见（例如使用 NFS）。&lt;br&gt;
下面的例子中将字符串 {shell}??????{/shell} 替换为你的实际的主机名。&lt;br&gt;
注意：远程运行任务的主机环境可能与本地运行的环境不同。这取决于你的系统如何设置。&lt;br&gt;
head.h 中已经设置正确的 PATH，可以使用 child command。&lt;br&gt;
如果没有这事，在 head.h 中调用 {shell}ecflow_client –init{/shell} 前添加下面的行：&lt;/p&gt;
&lt;pre&gt;export PATH=$PATH:/usr/local/apps/ecflow/%ECF_VERSION%/bin&lt;/pre&gt;
&lt;p&gt;使用 ssh 需要远程主机上配置好 public key。检查不用密码是否能登陆到远程主机。如果需要输入密码，则需要将你的 pulic key 添加到远程机器上。执行下面的命令：&lt;/p&gt;
&lt;pre class="lang:shell"&gt;REMOTE_HOST=??????
ssh $USER@$REMOTE_HOST mkdir -p \$HOME/.ssh
cat $HOME/.ssh/id_rsa.pub || ssh-keygen -t rsa -b 2048
cat $HOME/.ssh/id_rsa.pub | ssh $USER@$REMOTE_HOST 'cat &amp;gt;&amp;gt; $HOME/.ssh/authorized_keys'&lt;/pre&gt;
&lt;p&gt;修改 family f5，是所有任务都在远程服务器上运行&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.3 —— Limit</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-3-limit/</link><pubDate>Fri, 26 Feb 2016 10:14:24 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-3-limit/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*limits 提供简单的负载管理，限制提交到某个 ecflow_server 上的作业数目。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;suite 设计者使用两种触发器：&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;data dependency trigger：由 trigger 关键词设置&lt;/li&gt;
&lt;li&gt;courtesy trigger：由 limit 关键词设置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;trigger 是第一种触发器。第二种用于防止同时运行过多的作业，实际上是一种人工的作业排队方法。因为 ecflow 不区分这两种触发器，不利于后续维护。所以引入 limit。&lt;/p&gt;
&lt;h2 id="inlimit"&gt;inlimit&lt;/h2&gt;
&lt;p&gt;limits 与 inlimit 同时使用。&lt;br&gt;
首先定义limit：{shell}limit NAME N{/shell}，通常放在 suite 级&lt;br&gt;
接着将 定义一组想应用该 limit 的 task，将 {shell}inlimit NAME{/shell} 属性添加到节点。添加到 task 中将该 task 加入到 limit 组；添加到 family 将该 family 下的所有任务添加到 limit 组。&lt;br&gt;
limit 的效果是确保该组中同时运行的任务数不超过 N。一个节点可以被多个 limit 限制。&lt;/p&gt;
&lt;h2 id="ecf脚本"&gt;ecf脚本&lt;/h2&gt;
&lt;p&gt;创建有九个 task 的 family f5。&lt;br&gt;
在 {shell}$HOME/course/test/f5/{/shell} 目录下创建这些 ecf script 脚本，每个内容如下：&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.2 —— Repeat</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-2-repeat/</link><pubDate>Fri, 26 Feb 2016 09:56:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-2-repeat/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*有时需要重复多次运行某些 task 或 family，按某指定值循环。ecFlow 提供 repeat 属性实现该功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;repeat 可以按下列类型的序列循环：&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字符串&lt;/li&gt;
&lt;li&gt;整数&lt;/li&gt;
&lt;li&gt;日期&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整数和日期的序列由起始元素、终止元素和可选的间隔（默认为1）生成。ecFlow 会创建一个与 repeat 名字对应的变量，可以在脚本或 trigger 表达式中使用。&lt;/p&gt;
&lt;h2 id="ecf脚本"&gt;ecf脚本&lt;/h2&gt;
&lt;p&gt;创建新的 task {shell}/test/f4/f5/t1{/shell}&lt;/p&gt;
&lt;pre&gt;%include &amp;lt;head.h&amp;gt;
ecflow_client --label=info "My name is %NAME%" "My value is %VALUE%" "My date is %DATE%"
sleep %SLEEP%
%include &amp;lt;tail.h&amp;gt;&lt;/pre&gt;
&lt;h2 id="suite-definition"&gt;Suite definition&lt;/h2&gt;
&lt;p&gt;在 suite definition 中添加 repeat&lt;/p&gt;
&lt;h3 id="文本方式"&gt;文本方式&lt;/h3&gt;
&lt;p&gt;定义语法：&lt;/p&gt;
&lt;pre&gt;repeat ::= "repeat" &amp;gt;&amp;gt; repeat_type &amp;gt;&amp;gt; +nextline
repeat_type ::= repeat_date | repeat_day | repeat_month | repeat_year | repeat_integer | repeat_enumerated | repeat_string
repeat_day ::= "day" &amp;gt;&amp;gt; unsigned integer &amp;gt;&amp;gt; !ymd
repeat_month ::= “month" &amp;gt;&amp;gt; unsigned integer &amp;gt;&amp;gt; !ymd
repeat_year ::= "year" &amp;gt;&amp;gt; unsigned integer &amp;gt;&amp;gt; !ymd
repeat_integer ::= "integer" &amp;gt;&amp;gt; identifier &amp;gt;&amp;gt; integer &amp;gt;&amp;gt; " " &amp;gt;&amp;gt; integer &amp;gt;&amp;gt; " " &amp;gt;&amp;gt; integer
repeat_enumerated ::= "enumerated" &amp;gt;&amp;gt; identifier &amp;gt;&amp;gt; +identifier
repeat_string ::= "string" &amp;gt;&amp;gt; identifier &amp;gt;&amp;gt; +identifier
repeat_date ::= "date" &amp;gt;&amp;gt; identifier &amp;gt;&amp;gt; ymd &amp;gt;&amp;gt; ymd &amp;gt;&amp;gt; integer&lt;/pre&gt;
&lt;p&gt;下面以整型和日期为例说明。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4.1 —— Label</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-1-label/</link><pubDate>Fri, 26 Feb 2016 09:27:59 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-1-label/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*有时需要使用 ecflowview 查看任务的特殊信息，这就需要用到 label。label 是与 task 关联的字符串，可以使用 {shell}ecflow_client –label{/shell} 命令更新。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ecf-脚本"&gt;ecf 脚本&lt;/h2&gt;
&lt;p&gt;创建新的 family f3 和它的一个 task t1。&lt;br&gt;
创建相应的 ecf script，位于 {shell}$HOME/course/test/f3/t1.ecf{/shell}&lt;/p&gt;
&lt;pre class="lang:shell"&gt;%include &amp;lt;head.h&amp;gt;
n=1
while [[ $n -le 5 ]] # Loop 5 times
do
 msg="The date is now $(date)"
 ecflow_client --label=info "$msg" # Set the label
 sleep 60 # Wait a one minute
 (( n = $n + 1 ))
done
ecflow_client --label info "I have now finished my work."
%include &amp;lt;tail.h&amp;gt;&lt;/pre&gt;
&lt;h2 id="suite-definition"&gt;suite definition&lt;/h2&gt;
&lt;p&gt;下面的代码中省略之前的 family f1 和 family f2。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.4 —— 高级话题</title><link>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-e9ab98e7baa7e8af9de9a298/</link><pubDate>Fri, 26 Feb 2016 09:12:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-4-e9ab98e7baa7e8af9de9a298/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*下面章节介绍更高级的主题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Label&lt;br&gt;
Repeat&lt;br&gt;
Limit&lt;br&gt;
运行远程作业&lt;br&gt;
文件位置&lt;br&gt;
日期和时钟&lt;br&gt;
使用 Python 脚本&lt;br&gt;
面向对象 Suite&lt;br&gt;
Zombie&lt;/p&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.11 —— 缩进</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-11-e7bca9e8bf9b/</link><pubDate>Thu, 25 Feb 2016 17:47:43 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-11-e7bca9e8bf9b/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*文本方式支持首行缩进。但 Python 中缩进也是语法结构，会影响程序的含义。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Python 方式需要使用 with 语句实现缩进。&lt;br&gt;
下面将前一个例子用 with 语句改写。&lt;/p&gt;&lt;/p&gt;
&lt;pre class="lang:py"&gt;#!/usr/bin/env python2.7
import os
import ecflow
import sys
version = sys.version_info
if version[1] &amp;lt; 7:
 print "This example requires python version 2.7, but found : " + str(version)
 exit(0)
print "Creating suite definition"
with ecflow.Defs() as defs:
 with defs.add_suite("test") as suite:
 suite.add_variable("ECF_INCLUDE", os.path.join(os.getenv("HOME"), "course"))
 suite.add_variable("ECF_HOME", os.path.join(os.getenv("HOME"), "course"))
 with suite.add_family("f1") as f1:
 f1.add_variable("SLEEP", 20)
 f1.add_task("t1").add_meter("progress", 1, 100, 90)
 f1.add_task("t2").add_trigger("t1 eq complete").add_event("a").add_event("b")
 f1.add_task("t3").add_trigger("t2:a")
 f1.add_task("t4").add_trigger("t2 eq complete").add_complete("t2:b")
 f1.add_task("t5").add_trigger("t1:progress ge 30")
 f1.add_task("t6").add_trigger("t1:progress ge 60")
 f1.add_task("t7").add_trigger("t1:progress ge 90")
 with suite.add_family("f2") as f2:
 f2.add_variable("SLEEP", 20)
 f2.add_task("t1").add_time("00:30 23:30 00:30")
 f2.add_task("t2").add_day("sunday")
 f2.add_task("t3").add_date(1, 0, 0).add_time(12, 0)
 f2.add_task("t4").add_time(0, 2, True)
 f2.add_task("t5").add_time(0, 2)
 print defs
 print "Checking job creation: .ecf -&amp;gt; .job0"
 print defs.check_job_creation()
 print "Checking trigger expressions"
 print defs.check()
 print "Saving definition to file 'test.def'"
 defs.save_as_defs("test.def")&lt;/pre&gt;
&lt;p&gt;另外一种方式是使用 ecf.py，但没找到这个脚本。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.10 —— 时间依赖</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-10-e697b6e997b4e4be9de8b596/</link><pubDate>Thu, 25 Feb 2016 17:40:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-10-e697b6e997b4e4be9de8b596/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*有时希望在某个特定时间点运行某个任务，或者每三个小时运行，或者每月第一天，或者星期一。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ecFlow 支持 date 和 time 依赖。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="依赖种类"&gt;依赖种类&lt;/h2&gt;
&lt;h3 id="时间"&gt;时间&lt;/h3&gt;
&lt;p&gt;绝对时间：在确定时间点运行&lt;br&gt;
相对时间： 相对于 suite 的启动时间&lt;br&gt;
时间依赖可以按常规间隔重复。一旦所有时间点都运行结束，节点变为 complete 状态&lt;/p&gt;
&lt;pre&gt;time 23:00 # at next 23:00
time 10:00 20:00 01:00 # every hour from 10am to 8pm
time +00:01 # one minute after the suite has begun
time +00:10 01:00 00:05 # 10 to 60 minutes after begin every 5 minutes&lt;/pre&gt;
&lt;p&gt;最后一个示例中，如果任务运行超过5分钟，则会错过时间点。&lt;/p&gt;
&lt;h3 id="日期date-or-day"&gt;日期（date or day）&lt;/h3&gt;
&lt;p&gt;日期依赖使用 {shell}date{/shell} 或 {shell}day{/shell} 指定。日期依赖都是绝对的，但可以使用通配符&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.9 —— 添加 meter</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-9-e6b7bbe58aa0-meter/</link><pubDate>Thu, 25 Feb 2016 17:20:28 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-9-e6b7bbe58aa0-meter/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*meter 类似 event，但不同于值为 bool 类型（on/off）的 event，meter 的值可以取一个范围内的整数。其他任务会在 meter 达到某个特定值时被处罚。类似 event，meter 有名字，一个 task 可以包含多个 meter。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ecf脚本"&gt;Ecf脚本&lt;/h2&gt;
&lt;p&gt;创建新的 task（t5，t6,和t7），当 task t1 的 meter 达到特定值时被触发。为了通知 ecflow_server，task 必须调用 {shell}ecflow_client –meter{/shell} 命令。&lt;/p&gt;
&lt;h3 id="t1ecf"&gt;t1.ecf&lt;/h3&gt;
&lt;pre class="lang:shell"&gt;%include &amp;lt;head.h&amp;gt;
echo "I will now sleep for %SLEEP% seconds"
sleep %SLEEP%
n=1
while [[ $n -le 100 ]] # Loop 100 times
do
 sleep 1 # Wait a short time
 ecflow_client --meter=progress $n # Notify ecFlow
 (( n = $n + 1 ))
done
%include &amp;lt;tail.h&amp;gt;&lt;/pre&gt;
&lt;h2 id="suite-definition"&gt;Suite definition&lt;/h2&gt;
&lt;p&gt;在 suite definition 中见添加 meter。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.8 —— 添加 complete</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-8-e6b7bbe58aa0-complete/</link><pubDate>Thu, 25 Feb 2016 17:12:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-8-e6b7bbe58aa0-complete/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*有时希望在满足某条件时不运行某任务，条件可以用 event 标识。例如，{shell}event t2:b{/shell} 可能暗示 task t2 没有生成期待的结果，所以我们不需要运行 task t4.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种情况下，可以使用 complete 表达式，与关键词 trigger 有类似的语法，但在满足条件时将任务置为 complete 状态而不运行该任务。&lt;br&gt;
当 ecflow_server 尝试启动一个 task 时，会检查 trigger 和 complete 表达式。如果满足 complete 表达式，任务就会被设为 complete 状态。检查时，complete 表达式优先于 trigger 表达式。&lt;br&gt;
complete 可以用于 task 间、family 间或者两者混合，也可以与 trigger 联合使用。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="suite-definition"&gt;Suite Definition&lt;/h2&gt;
&lt;p&gt;在 suite definition 中定义 complete。&lt;/p&gt;
&lt;h3 id="text"&gt;Text&lt;/h3&gt;
&lt;p&gt;# Definition of the suite test.&lt;br&gt;
suite test&lt;br&gt;
edit ECF_INCLUDE “$HOME/course” # replace ‘$HOME’ with the path to your home directory&lt;br&gt;
edit ECF_HOME “$HOME/course”&lt;br&gt;
family f1&lt;br&gt;
edit SLEEP 20&lt;br&gt;
task t1&lt;br&gt;
task t2&lt;br&gt;
trigger t1 eq complete&lt;br&gt;
event a&lt;br&gt;
event b&lt;br&gt;
task t3&lt;br&gt;
trigger t2:a&lt;br&gt;
task t4&lt;br&gt;
trigger t2 eq complete&lt;br&gt;
complete t2:b&lt;br&gt;
endfamily&lt;br&gt;
endsuite&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.7 —— 添加事件</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-7-e6b7bbe58aa0e4ba8be4bbb6/</link><pubDate>Thu, 25 Feb 2016 16:52:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-7-e6b7bbe58aa0e4ba8be4bbb6/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*有时，等待一个任务结束还不够。如果任务产生多个结果，另一个任务或许需要在第一个结果生成时就开始运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ecFlow 引入事件 event 概念。event 是任务运行时发送给 ecflow_server 的一个消息，每个任务可以设置多个事件。event 是 trigger 的一种。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="ecf-script"&gt;Ecf Script&lt;/h2&gt;
&lt;p&gt;我们将创建新的 task(t3,t4),它们被 t2 发出的事件触发。通过拷贝 t1 创建 t3 和 t4 的 ecf script。为了通知 ecflow_server，task（下面示例中的 t2）必须调用 {shell}ecflow_client –event{/shell}。&lt;/p&gt;
&lt;h3 id="t2ecf"&gt;t2.ecf&lt;/h3&gt;
&lt;pre&gt;%include
echo "I will now sleep for %SLEEP% seconds"
sleep %SLEEP%
ecflow_client --event a # Set the first event
sleep %SLEEP% # Sleep a bit more
ecflow_client --event b # Set the second event
sleep %SLEEP% # A last nap...
%include&lt;/pre&gt;
&lt;h2 id="suite-definition"&gt;Suite Definition&lt;/h2&gt;
&lt;h3 id="text"&gt;Text&lt;/h3&gt;
&lt;pre&gt;# Definition of the suite test.
suite test
 edit ECF_INCLUDE "$HOME/course" # replace '$HOME' with the path to your home directory
 edit ECF_HOME "$HOME/course"
 family f1
 edit SLEEP 20
 task t1
 task t2
 trigger t1 eq complete
 event a
 event b
 task t3
 trigger t2:a
 task t4
 trigger t2:b
 endfamily
endsuite&lt;/pre&gt;
&lt;h3 id="python"&gt;Python&lt;/h3&gt;
&lt;pre class="lang:py"&gt;#!/usr/bin/env python2.7
import os
import ecflow
def create_family_f1():
 f1 = ecflow.Family("f1")
 f1.add_variable("SLEEP", 20)
 f1.add_task("t1")
 t2 = f1.add_task("t2")
 t2.add_trigger("t1 eq complete")
 t2.add_event("a")
 t2.add_event("b")
 f1.add_task("t3").add_trigger("t2:a")
 f1.add_task("t4").add_trigger("t2:b")
 return f1
print "Creating suite definition"
defs = ecflow.Defs()
suite = defs.add_suite("test")
suite.add_variable("ECF_INCLUDE", os.path.join(os.getenv("HOME"), "course"))
suite.add_variable("ECF_HOME", os.path.join(os.getenv("HOME"), "course"))
suite.add_family( create_family_f1() )
print defs
print "Checking job creation: .ecf -&amp;gt; .job0"
print defs.check_job_creation()
print "Checking trigger expressions"
print defs.check()
print "Saving definition to file 'test.def'"
defs.save_as_defs("test.def")&lt;/pre&gt;
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;更新 test.def 或 test.py&lt;/li&gt;
&lt;li&gt;编辑 t2.ecf，添加 ecflow_client –event 调用&lt;/li&gt;
&lt;li&gt;拷贝 t1.ecf 为 t3.ecf 和 t4.ecf&lt;/li&gt;
&lt;li&gt;替换 suite&lt;/li&gt;
&lt;li&gt;在 ecflowview 中观察任务&lt;br&gt;
&lt;img class="alignnone" src="http://ww2.sinaimg.cn/mw690/4afdac38jw1f1bodyuv1nj20d207xt9e.jpg" alt="" width="470" height="285" /&gt;&lt;/li&gt;
&lt;li&gt;查看 t3 的触发器&lt;img class="alignnone" src="http://ww2.sinaimg.cn/mw690/4afdac38jw1f1bodz9qw8j20bt08t0t7.jpg" alt="" width="425" height="317" /&gt;&lt;/li&gt;
&lt;li&gt;查看 t2 的触发器&lt;img class="alignnone" src="http://ww4.sinaimg.cn/mw690/4afdac38jw1f1bodzfv0jj20hx07jwff.jpg" alt="" width="645" height="271" /&gt;&lt;img class="alignnone" src="//ww2.sinaimg.cn/mw690/4afdac38jw1f1bodzqfaqj20hq07w3zp.jpg" alt="" width="638" height="284" /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="词汇表"&gt;词汇表&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-event"&gt;event&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecflow-server"&gt;ecflow_server&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-task"&gt;task&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecf-script"&gt;ecf script&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecflow-client"&gt;ecflow_client&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-child-command"&gt;child command&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-suite"&gt;suite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecflowview"&gt;ecflowview&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.6 —— 添加触发器</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-6-e6b7bbe58aa0e8a7a6e58f91e599a8/</link><pubDate>Thu, 25 Feb 2016 16:35:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-6-e6b7bbe58aa0e8a7a6e58f91e599a8/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*前一个练习中，我们看到两个 task 同时运行。我们想确保 t2 只在 t1 完成后再运行，因此需要定义触发器 trigger。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Trigger 用来声明两个任务间的依赖关系（dependencies），例如，二号任务可能需要一号任务生成的数据。当 ecFlow 尝试启动一个任务时，它会检查 trigger 表达式。如果条件满足，任务启动，相反任务保持 queued 状态。Trigger 可以用在任务间、family 间或者两者的混合。&lt;br&gt;
记住下面两条规则&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;所有任务都完成时，family 才完成&lt;/li&gt;
&lt;li&gt;任务的 trigger 和所有父节点的 trigger 都满足时，任务才会启动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个节点只能有一个 trigger 表达式，但可以构建非常复杂的表达式（记住父节点的 trigger 也是隐含的 trigger）。&lt;br&gt;
有时 trigger 用于防止同一时间运行过多的任务。这种情况下更好的方法就是使用 limit （后面将会介绍 limit）。&lt;br&gt;
trigger 中的表达式可以以使用节点的全名，例如&lt;br&gt;
{shell}/test/f1/t1{/shell} 表示 task t1&lt;br&gt;
{shell}/test/f1{/shell} 表示 family f1&lt;/p&gt;
&lt;pre&gt;trigger /test/f1/t1 == complete&lt;/pre&gt;
&lt;p&gt;一些情况下，ecFlow 接受相对名称，例如 {shell}../t1{shell}&lt;br&gt;
Trigger 可以非常复杂，ecFlow 支持所有的条件语句（not、and、or 等等），并且 trigger 可以引用节点属性，例如 event, meter, variable, repeat 和生成变量。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.5 —— 变量继承</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-5-e58f98e9878fe7bba7e689bf/</link><pubDate>Thu, 25 Feb 2016 16:22:22 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-5-e58f98e9878fe7bba7e689bf/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*之前的章节中，我们看到如何为 task 定义变量。当同一 family 下的所有 task 都共享同一个变量值时，该值可以定义在 family 层。这就是变量继承（variable inheritance）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面的例子中，也可将变量定义在 suite 层，得到相同的结果。&lt;br&gt;
变量从父节点继承。子节点可以重新定义变量，这种情况下使用新的变量值。生成的变量（generated variables）也可以重新定义，但不推荐这么做，除非你很清楚可能出现的后果。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="suite-definition"&gt;Suite Definition&lt;/h2&gt;
&lt;h3 id="text"&gt;Text&lt;/h3&gt;
&lt;pre&gt;# Definition of the suite test.
suite test
 edit ECF_INCLUDE "$HOME/course" # replace '$HOME' with the path to your home directory
 edit ECF_HOME "$HOME/course"
 family f1
 edit SLEEP 20
 task t1
 task t2
 endfamily
endsuite&lt;/pre&gt;
&lt;h3 id="python"&gt;python&lt;/h3&gt;
&lt;pre class="lang:python"&gt;#!/usr/bin/env python2.7
import os
import ecflow
def create_family_f1():
 f1 = ecflow.Family("f1" )
 f1.add_variable("SLEEP", 20)
 f1.add_task("t1")
 f1.add_task("t2")
 return f1
print "Creating suite definition"
defs = ecflow.Defs()
suite = defs.add_suite("test")
suite.add_variable("ECF_INCLUDE", os.path.join(os.getenv("HOME"), "course"))
suite.add_variable("ECF_HOME", os.path.join(os.getenv("HOME"), "course"))
suite.add_family( create_family_f1() )
print defs
print "Checking job creation: .ecf -&amp;gt; .job0"
print defs.check_job_creation()
print "Saving definition to file 'test.def'"
defs.save_as_defs("test.def")&lt;/pre&gt;
&lt;p&gt;生成的 def 文件&lt;br&gt;
# 4.0.9&lt;br&gt;
suite test&lt;br&gt;
edit ECF_HOME ‘/home/windroc/course’&lt;br&gt;
edit ECF_INCLUDE ‘/home/windroc/course’&lt;br&gt;
family f1&lt;br&gt;
edit SLEEP ’20’&lt;br&gt;
task t1&lt;br&gt;
task t2&lt;br&gt;
endfamily&lt;br&gt;
endsuite&lt;br&gt;
&lt;img class="alignnone" src="http://ww3.sinaimg.cn/large/4afdac38jw1f1bnl5s4rwj20c405z3z0.jpg" alt="" width="436" height="215" /&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.4 —— ecFlow 变量</title><link>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-4-ecflow-e58f98e9878f/</link><pubDate>Thu, 25 Feb 2016 16:02:54 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-25-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-4-ecflow-e58f98e9878f/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*我们已经看到 ecFlow 使用一些变量，比如 ECF_HOME。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;共有三种变量：&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ecFlow 使用的变量，例如ECF_HOME&lt;/li&gt;
&lt;li&gt;用户定义的变量，不应该以 ECF 开头，推荐使用大写字母来定义变量。&lt;/li&gt;
&lt;li&gt;ecFlow 生成的变量，可以在 job 中使用，例如包含 suite 的日期 ECF_DATE。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ecf脚本"&gt;Ecf脚本&lt;/h2&gt;
&lt;p&gt;之前的例子中，我们复制 t1.ecf 为 t2.ecf。编辑这两个文件，以变量 SLEEP 为参数调用 unix 的 sleep 命令。&lt;/p&gt;
&lt;pre&gt;%include
echo "I will now sleep for %SLEEP% seconds"
sleep %SLEEP%
%include&lt;/pre&gt;
&lt;h2 id="suite-definition"&gt;suite definition&lt;/h2&gt;
&lt;p&gt;添加变量到 suite definition&lt;/p&gt;
&lt;h3 id="text"&gt;Text&lt;/h3&gt;
&lt;p&gt;# Definition of the suite test.&lt;br&gt;
suite test&lt;br&gt;
edit ECF_INCLUDE “$HOME/course” # replace ‘$HOME’ with the path to your home directory&lt;br&gt;
edit ECF_HOME “$HOME/course”&lt;br&gt;
family f1&lt;br&gt;
task t1&lt;br&gt;
edit SLEEP 20&lt;br&gt;
task t2&lt;br&gt;
edit SLEEP 20&lt;br&gt;
endfamily&lt;br&gt;
endsuite&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.3 —— Families</title><link>https://blog.perillaroc.wang/post/2016/2016-02-17-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-3-families/</link><pubDate>Wed, 17 Feb 2016 16:56:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-17-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-3-families/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*可以将任务组织成类似 unix 文件系统的树形结构，其中 task 类似文件，而 family 类似文件夹。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;suite 是附带额外属性的 family （参看 &lt;strong&gt;Dates and Clocks&lt;/strong&gt;）。类似日暮，family 可以包含其它 family。类似目录，不同的 family 中的 task 可以重名。&lt;br&gt;
除非指定文件位置，否则 ecFlow 认为 suite 的结构对应文件系统中任务文件的位置。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="ecf脚本"&gt;Ecf脚本&lt;/h2&gt;
&lt;p&gt;在下面的 suite definition 中，我们将创建包含task t1 和 task t2 的 family f1。需要创建目录 $HOME/course/test/f1，并将 t1.ecf 和 t2.ecf 移动到该目录中。ecflow job 文件和 output 文件将在该目录中创建。&lt;br&gt;
因为我们将脚本移动到另外的目录中，ecFlow 无法找到脚本所在目录的父目录中的两个头文件 head.h 和 tail.h。可以修改脚本，在上两级目录搜索头文件，但这种方式太累赘。&lt;br&gt;
解决方法就是定义一个特殊的 ecFlow 变量 ECF_INCLUDE。ECF_INCLUDE 变量指示包含头文件的目录。参看 pre-prossing.&lt;br&gt;
使用尖括号时，ecFlow 首先检查 ECF_INCLUDE 变量是否被定义。如果存在，则检查 %ECF_INCLUDE%/head.h 是否存在，不存在则查找 %ECF_HOME%/head.h 是否存在。通过这种机制，可以讲特殊的头文件放到 ECF_INCLUDE 目录下，将通用的头文件放到 ECF_HOME 目录下。更多详细信息请参看 directives。&lt;br&gt;
我们需要对 ecf script 脚本作如下修改：&lt;br&gt;
从&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.2 —— 添加说明</title><link>https://blog.perillaroc.wang/post/2016/2016-02-17-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-2-e6b7bbe58aa0e8afb4e6988e/</link><pubDate>Wed, 17 Feb 2016 16:47:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-17-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-2-e6b7bbe58aa0e8afb4e6988e/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*manual page 使 ecf script 中的文档可以在 ecflowview 中看到。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;说明页是指令 %manual 和 %end 之前的所有文本的组合。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="修改-t2ecf"&gt;修改 t2.ecf&lt;/h2&gt;
&lt;p&gt;%manual&lt;br&gt;
Manual for task t2&lt;br&gt;
Operations: if this task fails, set it to complete and report next working day&lt;br&gt;
Analyst: Check something ?&lt;br&gt;
%end&lt;br&gt;
%include “../head.h”&lt;br&gt;
echo “I am part of a suite that lives in %ECF_HOME%”&lt;br&gt;
%include “../tail.h”&lt;br&gt;
%manual&lt;br&gt;
There can be multiple manual pages in the same file.&lt;br&gt;
When viewed they are simply concatenated.&lt;br&gt;
%end&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3.1 —— 添加另一个任务</title><link>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-1-e6b7bbe58aa0e58fa6e4b880e4b8aae4bbbbe58aa1/</link><pubDate>Wed, 03 Feb 2016 15:16:36 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-1-e6b7bbe58aa0e58fa6e4b880e4b8aae4bbbbe58aa1/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*我们来添加一个新任务名为t2，需要修改 suite definition 文件并添加一个新的脚本。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 $HOME/course/test 中创建文件 t2.ecf，直接复制 t1.ecf 即可。&lt;br&gt;
首先修改 suite definition&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="文本方式"&gt;文本方式&lt;/h2&gt;
&lt;p&gt;在重新加载 suite 的任何部分前推荐先将 suite 挂起（suspend）。在 ecflowview 中右键点击suite，选择 Suspend。当修改完成后，右键点击 suite，选择 Resume。&lt;br&gt;
&lt;img class="alignnone" src="http://ww1.sinaimg.cn/mw690/4afdac38jw1f0m62edlowj209o05ljrk.jpg" alt="" width="348" height="201" /&gt;&lt;br&gt;
挂起后，suite 颜色会改变&lt;br&gt;
&lt;img class="alignnone" src="http://ww1.sinaimg.cn/mw690/4afdac38jw1f0m62ench0j205j00zgli.jpg" alt="" width="199" height="35" /&gt;&lt;br&gt;
恢复 suite&lt;br&gt;
&lt;img class="alignnone" src="http://ww3.sinaimg.cn/mw690/4afdac38jw1f0m62ey21gj207k05t74i.jpg" alt="" width="272" height="209" /&gt;&lt;br&gt;
添加新任务t2的 def 文件&lt;/p&gt;
&lt;pre&gt;# Definition of the suite test
suite test
 edit ECF_HOME "$HOME/course" # replace '$HOME' with the path to your home directory
 task t1
 task t2
endsuite&lt;/pre&gt;
&lt;p&gt;注：与之前一样，使用实际的home目录替换 $HOME&lt;br&gt;
在 test 目录下，复制 t1.ecf，创建 task t2 的脚本 t2.ecf。&lt;br&gt;
重新加载 def 文件&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.3 —— 进一步</title><link>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-e8bf9be4b880e6ada5/</link><pubDate>Wed, 03 Feb 2016 15:11:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-3-e8bf9be4b880e6ada5/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*使用 ecFlow 提供的一些功能构建更复杂的 suite。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;添加更多的任务，并学习如何组织为 family。&lt;br&gt;
如何定义任务间的依赖关系。&lt;br&gt;
如何使用 ecFlow 控制何时运行任务。&lt;/p&gt;&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.9 —— 使用ecFlowview</title><link>https://blog.perillaroc.wang/post/2016/2016-02-03-1750/</link><pubDate>Wed, 03 Feb 2016 09:54:36 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-03-1750/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*我们看下 ecFlow 的 GUI —— ecFlowview，命令行下输入 ecflowview&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;程序运行后：&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从 Edit 菜单中选择 Preference&lt;/li&gt;
&lt;li&gt;接下来点击 Servers 标签，输入 ecflow 服务器的详细信息。为 ecflow 服务器取个名字，添加Host和Port号，点击添加按钮&lt;/li&gt;
&lt;/ul&gt;
&lt;img class="alignnone" src="http://ww4.sinaimg.cn/large/4afdac38jw1f0lwqazro4j20kj0fl75t.jpg" alt="" width="739" height="561" /&gt; 
可以从 ecflowview 的主菜单的 Server 菜单中选择 ecflow_server。会在主窗体中显示服务器信息： 
&lt;img class="alignnone" src="http://ww1.sinaimg.cn/mw690/4afdac38jw1f0lwqba3kjj20dn053t97.jpg" alt="" width="491" height="183" /&gt; 
黄色的盒子叫做 node。在 test 上点击鼠标中键 
&lt;img class="alignnone" src="http://ww2.sinaimg.cn/mw690/4afdac38jw1f0lwqbl3bxj20jt05pq3m.jpg" alt="" width="690" height="198" /&gt; 
现在可以查看 ecf script，job file 和 task t1 的输出文件。点击t1，然后点击 script 图标，会弹出一个窗口显示任务脚本： 
&lt;img class="alignnone" src="http://ww2.sinaimg.cn/mw690/4afdac38jw1f0lwqbtl3rj20hu0enq41.jpg" alt="" width="642" height="527" /&gt; 
点击不同的标签查看 ECF job 文件或者输出文件。如果想要在不同的窗口查看输出文件，点击 output 图标。 
如果想要重新运行 suite，鼠标右键点击 test，在弹出菜单中选择 requeue 
如果没有出现 requeue 选项，在 Edit 菜单中选择 Preferences&amp;#8230;，并将用户等级提升至 Administrator 
&lt;img class="alignnone" src="http://ww1.sinaimg.cn/mw690/4afdac38jw1f0lwqc5f4rj20g50aujrv.jpg" alt="" width="581" height="390" /&gt; 
注意 node 颜色的变化，颜色的变化反应 node 的 status。 
&lt;img class="alignnone" src="http://ww4.sinaimg.cn/mw690/4afdac38jw1f0lwqcfstyj20jr05pdgk.jpg" alt="" width="690" height="199" /&gt; 
ecFlowview 使用鼠标的三个按钮实现不同的操作。下面的图显示 ecFlowview 中如何使用鼠标按钮： 
&lt;img class="alignnone" src="http://ww3.sinaimg.cn/mw690/4afdac38jw1f0lwqcrgp0j20a304vdg1.jpg" alt="" width="363" height="175" /&gt; 
&lt;h2 id="任务"&gt;任务&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;探索 ecFlowview 的菜单和窗口&lt;/li&gt;
&lt;li&gt;作业状态变化与 ecflowview 窗口中展现这些变化有一段较长的延时。想要更快地更新到当前状态，请点击红色状态按钮。&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>ecFlow学习笔记02.2.8 —— 检查结果</title><link>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-8-e6a380e69fa5e7bb93e69e9c/</link><pubDate>Wed, 03 Feb 2016 08:59:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-8-e6a380e69fa5e7bb93e69e9c/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*查看我们的 suite 的运行状态，输入：&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ ecflow_client --get_stat
# 4.0.9
defs_state STATE state&amp;gt;:complete flag:message state_change:72 modify_change:19
suite test # begun:1 state:complete
 edit ECF_HOME '/home/windroc/course'
 calendar initTime:2016-Feb-02 07:26:50 suiteTime:2016-Feb-02 07:27:00 duration:00:00:10 initLocalTime:2016-Feb-02 07:26:50 lastTime:2016-Feb-02 07:27:00 calendarIncrement:00:00:10
 task t1 # try:1 state:complete
endsuite&lt;/pre&gt;
&lt;p&gt;上述命令会从服务其中检索 suite definition ，并显示每个节点的状态。&lt;br&gt;
查看 task t1，如果t1是 complete 状态，并且 suite 是 complete 状态，那么运行成功。如果不是这种情况，则可能会有 aborted 状态。&lt;br&gt;
请检查 ecf script 的目录。服务器在ecf script相同的目录下创建 job file，名为 t1.job1。比较 t1.ecf，head.h，tail.h 和 t1.job1。作业的输出文件也放在ecf script 的目录下，名为 t1.1。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.7 —— 启动suite</title><link>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-7-e590afe58aa8suite/</link><pubDate>Wed, 03 Feb 2016 08:52:57 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-03-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-7-e590afe58aa8suite/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*ecflow_start.sh 脚本会自动启动 ecflow_server。手动启动 ecFlow 后，服务器处于 halted 状态，需要 restart 服务器。halted 状态的服务器不会调度任务。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="文本方式"&gt;文本方式&lt;/h2&gt;
&lt;p&gt;检查服务器的状态，输入下列 unix 命令&lt;/p&gt;
&lt;pre&gt;ecflow_client --stats&lt;/pre&gt;
&lt;p&gt;运行结果&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ ecflow_client --stats
Server statistics
 Version Ecflow version(4.0.9) boost(1.53.0) compiler(gcc 4.9.2) protocol(TEXT_ARCHIVE) Compiled on Jan 12 2016 05:57:30
 Status RUNNING
 Host ubuntu
 Port 2500
 Up since 2016-Jan-21 03:11:41
 Job sub' interval 60s
 ECF_HOME /home/windroc/course
 ECF_LOG /home/windroc/course/ubuntu.2500.ecf.log
 ECF_CHECK /home/windroc/course/ubuntu.2500.check
 Check pt interval 120s
 Check pt mode CHECK_ON_TIME
 Check pt save time alarm 30s
 Number of Suites 1
 Request's per 1,5,15,30,60 min 0.00 0.00 0.00 0.00 0.00
 Restart server 1
 Ping 10
 Server version 8
 Sync 12
 News 623
 Load definition 4
 Node delete 2
 stats cmd 1&lt;/pre&gt;
&lt;p&gt;如果 ecflow_server 处于 halted 状态，需要重新启动服务器&lt;br&gt;
手动进入 halted 状态&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.6 —— 加载文件</title><link>https://blog.perillaroc.wang/post/2016/2016-02-02-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-6-e58aa0e8bdbde69687e4bbb6/</link><pubDate>Tue, 02 Feb 2016 16:25:59 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-02-02-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-6-e58aa0e8bdbde69687e4bbb6/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*下一步就是让 ecflow_server 知道你的 suite，或者称为加载 suite definition 文件。这一步将检查 test.def 文件，并向 ecflow_server 描述 suite。可以通过多种方法实现，取决于 suite 的创建方式。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：从下面的两种方法中选择一种方法，避免两次加载 suite definition 时会出现的错误。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="文本"&gt;文本&lt;/h2&gt;
&lt;p&gt;在 course 目录执行下面的命令&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ ecflow_client --load=test.def --port=2500&lt;/pre&gt;
&lt;p&gt;这将检查并加载 suite definition 到 ecflow_server。如果检查失败，suite 不会被加载。之前的章节中提到过 ecflow_client，该命令被用在 head.h 和 tail.h 头文件中。&lt;br&gt;
注：请确保已经设置 ECF_PORT 环境变量，否则需要在命令行中使用 –port &amp;lt;port_number&amp;gt; 加载 suite 后的 ecflowview&lt;br&gt;
&lt;img src="http://ww2.sinaimg.cn/large/4afdac38gw1f0l2glxov3j20jc0odn2j.jpg" width="696" height="877" class="alignnone" /&gt;&lt;br&gt;
windroc 注：&lt;br&gt;
为了测试另一种方式，需要反向加载 suite，使用 ecflow_client –delete 命令：&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ ecflow_client --port=2500 --delete=/test
Are you sure want to delete nodes at paths:
 /test ? y&lt;/pre&gt;
&lt;h2 id="python"&gt;Python&lt;/h2&gt;
&lt;p&gt;使用 Python 脚本将 defs 写为 .def 定义文件，在 suite 定义比较复杂的时候对调试很有帮助。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.5 —— 理解客户端</title><link>https://blog.perillaroc.wang/post/2016/2016-01-29-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-5-e79086e8a7a3e5aea2e688b7e7abaf/</link><pubDate>Fri, 29 Jan 2016 08:41:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-29-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-5-e79086e8a7a3e5aea2e688b7e7abaf/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*所有与 ecflow_server 的通讯都需要通过 ecflow_client。任何与服务器的通讯都需要知道服务器的地址和端口。同一台主机中可能运行多个服务，每个服务都有唯一的端口号。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本教程将会给出通过 shell 和在Python 脚本中使用客户端的例子。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="客户端命令行接口"&gt;客户端命令行接口&lt;/h2&gt;
&lt;p&gt;客户端命令的列表：&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course/test$ ecflow_client --help
Client/server based work flow package:
Ecflow version(4.0.9) boost(1.53.0) compiler(gcc 4.9.2) protocol(TEXT_ARCHIVE) Compiled on Jan 12 2016 05:57:30
ecflow_client provides the command line interface, for interacting with the server:
Try:
 ecflow_client --help all # List all commands, verbosely
 ecflow_client --help summary # One line summary of all commands
 ecflow_client --help child # One line summary of child commands
 ecflow_client --help user # One line summary of user command
 ecflow_client --help &amp;lt;cmd&gt; # Detailed help on each command
Commands:
 abort alter begin ch_add ch_auto_add
 ch_drop ch_drop_user ch_register ch_rem ch_suites
 check checkJobGenOnly check_pt complete debug
 debug_server_off debug_server_on delete edit_history edit_script
 event file force force-dep-eval free-dep
 get get_state group halt help
 host init job_gen kill label
 load log meter migrate msg
 news order ping plug port
 reloadwsfile replace requeue restart restore_from_checkpt
 resume rid run server_load server_version
 show shutdown stats stats_reset status
 suites suspend sync sync_full terminate
 version wait why zombie_adopt zombie_block
 zombie_fail zombie_fob zombie_get zombie_kill zombie_remove&lt;/pre&gt;
&lt;p&gt;上面提到过，使用 ecflow_client 与服务器通讯需要设置 host 和 port，如下方法确定：&lt;br&gt;
默认主机和端口为：localhost:3141&lt;br&gt;
默认值被 ECF_NODE 和 ECF_PORT 环境变量覆盖&lt;br&gt;
环境变量被命令行参数 –port 和 –host 覆盖，并且可以用于 -help参数显示的任意shell层命令。&lt;br&gt;
例如在命令行 ping 一个服务可以输入命令：&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.4 —— 检查job生成</title><link>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-3-e6a380e69fa5jobe7949fe68890/</link><pubDate>Wed, 27 Jan 2016 21:22:00 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-3-e6a380e69fa5jobe7949fe68890/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*前面章节我们已经实现第一个task（t1.ecf 文件）。t1.ecf 脚本需要经过预处理生成 jobs file。这个过程由 ecflow_server 在将要运行 task 时自动完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们还可以在 suite definition 加载到 ecflow_server 前检查 job creation。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="文本方式"&gt;文本方式&lt;/h2&gt;
&lt;p&gt;检查脚本生成仅在Python方式下可用。&lt;br&gt;
如果 ecflow_server 无法定位 ecf script，请参看 &lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecf-file-location-algorithm"&gt;ecf file locaiton algorithm&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="python"&gt;Python&lt;/h2&gt;
&lt;p&gt;在 suite 定义加载到服务器前可以检查作业生成过程，检查包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;定位 ecf 脚本文件，对应 suite 定义中的每个 task&lt;/li&gt;
&lt;li&gt;进行预处理&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当 suite definition 较长且包含许多 ecf script 时，这种检查可以节省大量时间。&lt;br&gt;
检查 job creation 时需要注意一下几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查独立于 ecflow_server，所以 ECF_PORT 和 ECF_NODE 将被设为默认值。&lt;/li&gt;
&lt;li&gt;job 文件扩展名为 .job0，服务器生成的job文件扩展名为 job&amp;lt;1-n&amp;gt;，ECF_TRYNO将不为0.&lt;/li&gt;
&lt;li&gt;默认 job 文件将在 ecf 脚本同样目录下生成，请查看词汇表 ECF_JOB。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用 &lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+Python+Api#ecflow.Defs.check_job_creation"&gt;ecflow.Defs.check_job_creation&lt;/a&gt; 进行检查，修改 test.py&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.3 —— 定义第一个task</title><link>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-3-e5ae9ae4b989e7acace4b880e4b8aae4bbbbe58aa1/</link><pubDate>Wed, 27 Jan 2016 20:56:32 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-3-e5ae9ae4b989e7acace4b880e4b8aae4bbbbe58aa1/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*接下来，我们需要为 task t1 编写 ecf script。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;默认情况下，ecFlow 认为文件放在 ECF_HOME 目录下的一个目录结构中，该层次结构反应 suite 的层次关系。task t1 在 suite test 中，对应的 ecf script 应该在子目录 test 下。&lt;br&gt;
在 ECF_HOME 下创建 test 文件夹&lt;/p&gt;&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ mkdir test&lt;/pre&gt;
&lt;p&gt;在 test 中，创建 t1.ecf，文件内容为&lt;/p&gt;
&lt;pre class="lang:shell"&gt;%include "../head.h"
echo "I am part of a suite that lives in %ECF_HOME%"
%include "../tail.h"&lt;/pre&gt;
&lt;h2 id="脚本创建"&gt;脚本创建&lt;/h2&gt;
&lt;p&gt;在提交任务前，服务会将 ecf script 转化成一个 job file。这个过程叫做 job creation。&lt;br&gt;
包括在磁盘中定位 ecf script，然后预处理指令。这个步骤包括进行变量替换（variable substitution）。&lt;br&gt;
这将创建一个以.job结尾的文件，ecflow_server 将该文件提交给你的系统。&lt;br&gt;
在我们的例子中：&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.2 —— 理解头文件</title><link>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-2-e79086e8a7a3e5a4b4e69687e4bbb6/</link><pubDate>Wed, 27 Jan 2016 20:32:29 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-2-e79086e8a7a3e5a4b4e69687e4bbb6/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*前面的章节我们创建了一个 task。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个 task 都有对应的 ecf script，定义需要执行那些操作。脚本类似于 UNIX shell 脚本。&lt;br&gt;
但 ecf script 提供于 C 语言类似的预处理指令（pre-processing directive）和预定义变量。&lt;br&gt;
suite definition 中定义的变量可以在 ecf script 中使用，提供一种配置机制。&lt;br&gt;
默认人使用字符 % 表示预处理指令，其中一种就是 include 头文件。&lt;br&gt;
头文件用于向脚本中注入代码（与 C 语言的 include 头文件一样），提供一种代码复用的机制。如果相同的代码出现在不同的 ecf script 文件中，这些代码就应该放入一个头文件中。这样会提供一个单一的维护点。例如，每个 task 都需要建立与 ecflow_server 的通讯，并告诉服务器任务已经开始。这个样例代码就放在头文件中。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="headh"&gt;head.h&lt;/h2&gt;
&lt;p&gt;放在 ecf script 开头，作用：&lt;br&gt;
准备与 ecflow_server 通信的环境。&lt;br&gt;
定义脚本错误处理函数。当错误发生，通知服务器该任务 aborted。&lt;br&gt;
使用 child command 通知服务器作业已经开始。&lt;/p&gt;
&lt;pre class="lang:shell"&gt;#!/bin/ksh
set -e # stop the shell on first error
set -u # fail when using an undefined variable
set -x # echo script lines as they are executed
# Defines the variables that are needed for any communication with ECF
export ECF_PORT=%ECF_PORT% # The server port number
export ECF_NODE=%ECF_NODE% # The name of ecf host that issued this task
export ECF_NAME=%ECF_NAME% # The name of this current task
export ECF_PASS=%ECF_PASS% # A unique password
export ECF_TRYNO=%ECF_TRYNO% # Current try number of the task
export ECF_RID=$$ # record the process id. Also used for zombie detection
# Define the path where to find ecflow_client
# make sure client and server use the *same* version.
# Important when there are multiple versions of ecFlow
export PATH=/usr/local/apps/ecflow/%ECF_VERSION%/bin:$PATH
# Tell ecFlow we have started
ecflow_client --init=$$
# Define a error handler
ERROR() {
 set +e # Clear -e flag, so we don't fail
 wait # wait for background process to stop
 ecflow_client --abort=trap # Notify ecFlow that something went wrong, using 'trap' as the reason
 trap 0 # Remove the trap
 exit 0 # End the script
}
# Trap any calls to exit and errors caught by the -e flag
trap ERROR 0
# Trap any signal that may cause the script to fail
trap '{ echo "Killed by a signal"; ERROR ; }' 1 2 3 4 5 6 7 8 10 12 13 15&lt;/pre&gt;
&lt;h2 id="tailh"&gt;tail.h&lt;/h2&gt;
&lt;p&gt;放在 ecf script 文件结尾，通知服务器任务已经完成，使用 child command 中的 complete 命令。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2.1 —— 定义新的suite</title><link>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-1-e5ae9ae4b989e696b0e79a84suite/</link><pubDate>Wed, 27 Jan 2016 19:33:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-27-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-1-e5ae9ae4b989e696b0e79a84suite/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*有多种定义 suite definition 的方法，参看&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Definition+creation+strategies#strategy"&gt;Definition creation strategies&lt;/a&gt;。&lt;br&gt;
本教程介绍下面两种方式：&lt;/p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文本方法&lt;/li&gt;
&lt;li&gt;Python方法&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="文本方法"&gt;文本方法&lt;/h2&gt;
&lt;p&gt;创建 test.def&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ vim test.def&lt;/pre&gt;
&lt;p&gt;文件内容&lt;/p&gt;
&lt;pre&gt;# Definition of the suite test
suite test
 edit ECF_HOME "$HOME/course" # replace '$HOME' with the path to your home directory
 task t1
endsuite&lt;/pre&gt;
&lt;p&gt;windroc:&lt;br&gt;
与之前SMS的定义方式相同，只需要修改变量名，将SMS_XXX修改为 ECF_XXX。&lt;br&gt;
上述文件包含一个名为 test 的 suite 的 suite definition，该 suite 包含一个名为 t1 的 task。&lt;br&gt;
下面逐行解释含义&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;该行为注释。在 # 后到行尾之间的所有字符都会被忽略。&lt;/li&gt;
&lt;li&gt;定义一个名为 test 的新的 suite。&lt;/li&gt;
&lt;li&gt;定义一个 ecflow 变量，叫做 ECF_HOME。该变量定义定义名为 test 的 suite 可以再哪里找到所有的 unix 文件。余下的课程中，所有的文件名都相对于该目录。确保用你的 home 目录替换 $HOME。&lt;/li&gt;
&lt;li&gt;定义一个名为 t1 的 task。&lt;/li&gt;
&lt;li&gt;endsuite 结束名为 test 的 suite 的定义。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="python方法"&gt;python方法&lt;/h2&gt;
&lt;p&gt;创建一个 python 文件，例如命名为 test.py:&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.2 —— 开始使用</title><link>https://blog.perillaroc.wang/post/2016/2016-01-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-e5bc80e5a78be4bdbfe794a8/</link><pubDate>Tue, 26 Jan 2016 16:41:37 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-2-e5bc80e5a78be4bdbfe794a8/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*本节介绍如何使用 ecFlow，并假设操作系统中已经安装过 ecFlow。如果尚未安装，可以参考另一篇博文《&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="//windrocblog.sinaapp.com/?p=1602" title="ecFlow学习笔记01 —— 编译ecFlow"&gt;ecFlow学习笔记01 —— 编译&lt;/a&gt;》安装。&lt;br&gt;
为了使用 ecFlow，需要启动 ecflow server。首先准备教程需要的目录，在 home 目录下创建 course 目录，并切换进该目录。&lt;/p&gt;&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~$ mkdir course
windroc@ubuntu:~$ cd course
windroc@ubuntu:~/course$&lt;/pre&gt;
&lt;h2 id="共享环境"&gt;共享环境&lt;/h2&gt;
&lt;p&gt;共享环境中多个用户和多个 ecFlow 服务器可以同时存在，通过使用启动脚本 ecflow_start.sh 实现。该脚本会使用由用户ID唯一确定的端口号在你的系统中启动 ecflow_server 服务进程。脚本默认在 $HOME/ecflow_server 目录中创建 ecFlow 的日志和 check point 文件。可以使用 -d 选项改变日志和归档点文件的位置，例如将这些文件放到课程目录里：&lt;/p&gt;
&lt;pre&gt;ecflow_start.sh -d $HOME/course&lt;/pre&gt;
&lt;p&gt;windroc：需要修改 ecflow_start.sh 脚本，注释掉下面一行&lt;/p&gt;
&lt;pre&gt;. /home/ma/emos/bin/ecflow_site.sh || :&lt;/pre&gt;
&lt;p&gt;启动 ecflow 服务：&lt;/p&gt;
&lt;pre&gt;windroc@ubuntu:~/course$ ecflow_start.sh -d $HOME/course
/usr/local/bin/ecflow_start.sh: 113: /usr/local/bin/ecflow_start.sh: [[: not found
[03:11:37 21.1.2016] Request( --ping :windroc ), Failed to connect to ubuntu:2500. After 2 attempts. Is the server running ?
Thu Jan 21 03:11:37 UTC 2016
User "1000" attempting to start ecf server on "ubuntu" using ECF_PORT "2500" and with:
ECF_HOME : "/home/windroc/course"
ECF_LOG : "ubuntu.2500.ecf.log"
ECF_CHECK : "ubuntu.2500.check"
ECF_CHECKOLD : "ubuntu.2500.check.b"
ECF_OUT : "/dev/null"
client version is Ecflow version(4.0.9) boost(1.53.0) compiler(gcc 4.9.2) protocol(TEXT_ARCHIVE) Compiled on Jan 12 2016 05:57:30
Checking if the server is already running on ubuntu and port 2500
[03:11:38 21.1.2016] Request( --ping :windroc ), Failed to connect to ubuntu:2500. After 2 attempts. Is the server running ?
Backing up check point and log files
OK starting ecFlow server...
Placing server into RESTART mode...
To view server on ecflowview - goto Edit/Preferences/Servers and enter
Name :
Host : ubuntu
Port Number : 2500&lt;/pre&gt;
&lt;p&gt;运行之后可以查看后台进程&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02.1 —— 介绍</title><link>https://blog.perillaroc.wang/post/2016/2016-01-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-1-e4bb8be7bb8d/</link><pubDate>Tue, 26 Jan 2016 16:02:44 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-26-ecflowe5ada6e4b9a0e7ac94e8aeb002-1-e4bb8be7bb8d/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 ecFlow 教程的一部分，完整教程请参看《&lt;a href="//windrocblog.sinaapp.com/?p=1710" title="ecFlow学习笔记02 —— 教程"&gt;ecFlow学习笔记02 —— 教程&lt;/a&gt;》&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;*这篇教程的目的是通过一个简单的示例介绍ecFlow的功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个章节介绍一个新概念，并提供一系列任务。大部分章节都附带在线ecflow文档的链接，便于读者查看。&lt;/p&gt;&lt;/p&gt;
&lt;h2 id="使用-ecflow-的步骤"&gt;使用 ecFlow 的步骤&lt;/h2&gt;
&lt;h3 id="1-编写-suite-定义"&gt;1. 编写 suite 定义&lt;/h3&gt;
&lt;p&gt;多个 task 可以组成 family，family 可以属于另外的 family 或者属于 suite。所有的实体（task，family，suite）都叫做 node，构成一个层次树。&lt;br&gt;
有两个主要方法向 ecflow_server 描述 suite 定义（suite definition）：文本文件，python API接口&lt;br&gt;
&lt;strong&gt;文本文件&lt;/strong&gt;&lt;br&gt;
不支持条件语句，不支持函数&lt;br&gt;
可以使用各种语言生成文本文件&lt;br&gt;
与 SMS/CDP 类似，便于移植&lt;br&gt;
语法参见《&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Definition+file+Grammar"&gt;Definition file Grammar&lt;/a&gt;》&lt;br&gt;
&lt;strong&gt;Python接口&lt;/strong&gt;&lt;br&gt;
推荐方式，提供更过的功能&lt;br&gt;
参见 &lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/ecFlow+Python+Api#python-api"&gt;ecFlow Python Api&lt;/a&gt;&lt;br&gt;
windroc：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;强烈建议使用 Python 接口，这也是 ecFlow 的优势之一。文本定义语法编写判断、循环及定义函数的能力很弱，def 文件很难复用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="词汇表"&gt;词汇表&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-suite-definition"&gt;suite definition&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-task"&gt;task&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-suite"&gt;suite&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-node"&gt;node&lt;/a&gt;&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Glossary#term-ecflow-server"&gt;ecflow_server&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="2-编写脚本"&gt;2. 编写脚本&lt;/h3&gt;
&lt;p&gt;ecf script 是对应suite定义中task的文本文件。脚本定义任务重需要运行的主要工作，包含child command调用，特殊注释，以及为用户提供信息的说明段落。&lt;br&gt;
child command 是 ecflow_client 的命令子集，实现与 ecflow_server 的通讯。这些命令通知服务器某任务已经开始，完成，出错，或设置某些事件。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记02 —— 教程</title><link>https://blog.perillaroc.wang/post/2016/2016-01-26-ecflow-notebook-tutorial/</link><pubDate>Tue, 26 Jan 2016 15:50:23 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2016/2016-01-26-ecflow-notebook-tutorial/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该教程的最新版已发布在GitHub上，请访问&lt;a href="https://perillaroc.github.io/ecflow-tutorial-cn/"&gt;ecflow-tutorial-cn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;教程来自 ECMWF 的 ecFlow 官方文档，参见&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Tutorial"&gt;https://software.ecmwf.int/wiki/display/ECFLOW/Tutorial&lt;/a&gt;&lt;br&gt;
分为以下几个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="//windrocblog.sinaapp.com/?p=1713" title="ecFlow学习笔记02.1 —— 介绍"&gt;介绍&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//windrocblog.sinaapp.com/?p=1718" title="ecFlow学习笔记02.2 —— 开始使用"&gt;开始使用&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.1 &lt;a title="ecFlow学习笔记02.2.1 —— 定义新的suite" href="//windrocblog.sinaapp.com/?p=1723"&gt;定义新的suite&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.2 &lt;a title="ecFlow学习笔记02.2.2 —— 理解头文件" href="//windrocblog.sinaapp.com/?p=1728"&gt;理解头文件&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.3 &lt;a title="ecFlow学习笔记02.2.3 —— 定义第一个task" href="//windrocblog.sinaapp.com/?p=1730"&gt;定义第一个task&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.4 &lt;a title="ecFlow学习笔记02.2.4 —— 检查job生成" href="//windrocblog.sinaapp.com/?p=1735"&gt;检查job生成&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.5 &lt;a title="ecFlow学习笔记02.2.5 —— 理解客户端" href="//windrocblog.sinaapp.com/?p=1738"&gt;理解客户端&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.6 &lt;a title="ecFlow学习笔记02.2.6 —— 加载文件" href="//windrocblog.sinaapp.com/?p=1740"&gt;加载文件&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.7 &lt;a title="ecFlow学习笔记02.2.7 —— 启动suite" href="//windrocblog.sinaapp.com/?p=1742"&gt;启动suite&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.8 &lt;a title="ecFlow学习笔记02.2.8 —— 检查结果" href="//windrocblog.sinaapp.com/?p=1744"&gt;检查结果&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 2.9 &lt;a title="ecFlow学习笔记02.2.9 —— 使用ecFlowview" href="//windrocblog.sinaapp.com/?p=1750"&gt;使用ecFlowview&lt;/a&gt;
&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;a href="//windrocblog.sinaapp.com/?p=1755" title="ecFlow学习笔记02.3 —— 进一步"&gt;进一步使用&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style="padding-left: 30px;"&gt;
 3.1 &lt;a title="ecFlow学习笔记02.3.1 —— 添加另一个任务" href="//windrocblog.sinaapp.com/?p=1757"&gt;添加另一个任务&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 3.2 &lt;a title="ecFlow学习笔记02.3.2 —— 添加说明" href="//windrocblog.sinaapp.com/?p=1762"&gt;添加说明&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 3.3 &lt;a title="ecFlow学习笔记02.3.3 —— Families" href="//windrocblog.sinaapp.com/?p=1765"&gt;Families&lt;/a&gt;
&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;
 3.4 &lt;a title="ecFlow学习笔记02.3.4 —— ecFlow 变量" href="//windrocblog.sinaapp.com/?p=1772"&gt;ecFlow 变量&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>SMS日志分析开发笔记01 —— 日志解析</title><link>https://blog.perillaroc.wang/post/2015/2015-10-09-smse697a5e5bf97e58886e69e90e5bc80e58f91e7ac94e8aeb001-e697a5e5bf97e8a7a3e69e90/</link><pubDate>Fri, 09 Oct 2015 15:21:47 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-10-09-smse697a5e5bf97e58886e69e90e5bc80e58f91e7ac94e8aeb001-e697a5e5bf97e8a7a3e69e90/</guid><description/></item><item><title>SMS日志分析开发笔记00——简介</title><link>https://blog.perillaroc.wang/post/2015/2015-09-30-smse697a5e5bf97e58886e69e90e9a1b9e79baee5bc80e58f91e7ac94e8aeb000-e7ae80e4bb8b/</link><pubDate>Wed, 30 Sep 2015 11:42:03 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-09-30-smse697a5e5bf97e58886e69e90e9a1b9e79baee5bc80e58f91e7ac94e8aeb000-e7ae80e4bb8b/</guid><description/></item><item><title>[2015.09.18] 消失的百度空间</title><link>https://blog.perillaroc.wang/post/2015/2015-09-18-2015-09-18-e6b688e5a4b1e79a84e799bee5baa6e7a9bae997b4/</link><pubDate>Fri, 18 Sep 2015 15:40:23 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-09-18-2015-09-18-e6b688e5a4b1e79a84e799bee5baa6e7a9bae997b4/</guid><description/></item><item><title>Ubuntu中使用SOCKS代理安装软件</title><link>https://blog.perillaroc.wang/post/2015/2015-07-03-ubuntu-use-socks-to-install-software/</link><pubDate>Fri, 03 Jul 2015 00:17:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-07-03-ubuntu-use-socks-to-install-software/</guid><description>&lt;p&gt;&lt;img src="%22http://ww4.sinaimg.cn/mw690/4afdac38jw1etovy3vqm6j206y01uq2r.jpg%22" alt=""&gt;&lt;/p&gt;
&lt;p&gt;在单位使用 apt-get 安装软件时常出现校验和不相符的问题，估计是缓存没有及时更新，导致没法正常更新 Ubuntu。可以通过使用代理解决这个问题。&lt;br&gt;
之前在 Digital Ocean 搭建了一个 Shadowsocks 服务器，可以使用 SOCKS 代理。&lt;/p&gt;
&lt;h2 id="linux下的shadowsocks客户端"&gt;Linux下的Shadowsocks客户端&lt;/h2&gt;
&lt;p&gt;需要首先安装一个 Shadowsocks 客户端，搭建本地的 SOCKS 代理。&lt;br&gt;
我使用 &lt;a href="https://github.com/librehat/shadowsocks-qt5"&gt;shadowsocks-qt5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装 shadowsocks-qt5&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo add-apt-repository ppa:hzwhuang/ss-qt5
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install shadowsocks-qt5&amp;lt;/pre&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ss-qt5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按照之前一篇文章的方法配置本地代理，参见《&lt;a href="//windrocblog.sinaapp.com/?p=1651" title="使用Digital Ocean和Shadowsocks科学上网"&gt;使用Digital Ocean和Shadowsocks科学上网&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="命令行中使用socks代理"&gt;命令行中使用SOCKS代理&lt;/h2&gt;
&lt;p&gt;tsocks 软件支持在 Linux 命令行中使用 SOCKS 代理。&lt;br&gt;
安装&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo apt-get install tsocks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改配置文件 &lt;code&gt;/etc/tsocks.conf&lt;/code&gt;，设置 SOCKS 服务器 ip 地址，端口等参数。
需要注意 local 的 ip 端中必须包含服务器的 ip 地址。例如&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;local = 127.0.0.1/255.0.0.0
...
server = 127.0.0.1
server_type =5
server_port = 1080&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用，在命令前加上 tsocks 就行。&lt;/p&gt;</description></item><item><title>安装GIT服务器：gitolite</title><link>https://blog.perillaroc.wang/post/2015/2015-06-23-e5ae89e8a385gite69c8de58aa1e599a8efbc9agitolite/</link><pubDate>Tue, 23 Jun 2015 15:03:52 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-06-23-e5ae89e8a385gite69c8de58aa1e599a8efbc9agitolite/</guid><description/></item><item><title>使用Digital Ocean和Shadowsocks科学上网</title><link>https://blog.perillaroc.wang/post/2015/2015-06-23-e4bdbfe794a8digital-oceane5928cshadowsockse7a791e5ada6e4b88ae7bd91/</link><pubDate>Tue, 23 Jun 2015 11:01:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-06-23-e4bdbfe794a8digital-oceane5928cshadowsockse7a791e5ada6e4b88ae7bd91/</guid><description/></item><item><title>利用argparse模块开发带复杂参数的命令行程序</title><link>https://blog.perillaroc.wang/post/2015/2015-06-02-e588a9e794a8argparsee6a8a1e59d97e5bc80e58f91e5b8a6e5a48de69d82e58f82e695b0e79a84e591bde4bba4e8a18ce7a88be5ba8f/</link><pubDate>Tue, 02 Jun 2015 16:46:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-06-02-e588a9e794a8argparsee6a8a1e59d97e5bc80e58f91e5b8a6e5a48de69d82e58f82e695b0e79a84e591bde4bba4e8a18ce7a88be5ba8f/</guid><description/></item><item><title>Flask模板与AngularJS结合</title><link>https://blog.perillaroc.wang/post/2015/2015-05-28-flaske6a8a1e69dbfe4b88eangularjse7bb93e59088/</link><pubDate>Thu, 28 May 2015 14:38:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-05-28-flaske6a8a1e69dbfe4b88eangularjse7bb93e59088/</guid><description/></item><item><title>React.js 中使用 D3.js 动态更新数据</title><link>https://blog.perillaroc.wang/post/2015/2015-05-15-use-d3-in-reactjs/</link><pubDate>Fri, 15 May 2015 11:07:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-05-15-use-d3-in-reactjs/</guid><description/></item><item><title>使用Flask SocketIO实现WebSocket</title><link>https://blog.perillaroc.wang/post/2015/2015-05-11-use-flask-socketio-to-implement-websocket/</link><pubDate>Mon, 11 May 2015 16:24:46 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-05-11-use-flask-socketio-to-implement-websocket/</guid><description>&lt;p&gt;使用 HTML 5 的 WebSocket 实现实时交互通信功能，替代 Ajax 轮训等方法，个人觉得比较适合实时监控类网站。
我尝试使用 Flask-SocketIO 实现支持 WebSocket 的服务器端，使用 socket.io 库实现客户端。&lt;/p&gt;
&lt;h2 id="一个简单的-flask-socketio-应用"&gt;一个简单的 Flask-SocketIO 应用&lt;/h2&gt;
&lt;p&gt;仅完成就简单的通讯功能。&lt;/p&gt;
&lt;h3 id="服务器端"&gt;服务器端&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; flask &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Flask, render_template
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; flask.ext.socketio &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SocketIO, emit
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Flask(__name__)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;debug &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config[&lt;span style="color:#e6db74"&gt;&amp;#39;SECRET_KEY&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;windroc-nwpc-project&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;socketio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SocketIO(app)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@app.route&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_index_page&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; render_template(&lt;span style="color:#e6db74"&gt;&amp;#39;index.html&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@socketio.on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;connect&amp;#39;&lt;/span&gt;, namespace&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/test&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_connect&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; emit(&lt;span style="color:#e6db74"&gt;&amp;#39;my response&amp;#39;&lt;/span&gt;, {&lt;span style="color:#e6db74"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;Connected&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;count&amp;#39;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@socketio.on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;my event&amp;#39;&lt;/span&gt;, namespace&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;/test&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test_message&lt;/span&gt;(message):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; emit(&lt;span style="color:#e6db74"&gt;&amp;#39;my response&amp;#39;&lt;/span&gt;, {&lt;span style="color:#e6db74"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;: message[&lt;span style="color:#e6db74"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#39;count&amp;#39;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; socketio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(app, host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;, port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5101&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建 Flask-SocketIO 应用的方法与普通的 Flask 应用相似。&lt;/p&gt;</description></item><item><title>Flask请求数据</title><link>https://blog.perillaroc.wang/post/2015/2015-05-06-flaske8afb7e6b182e695b0e68dae/</link><pubDate>Wed, 06 May 2015 21:58:32 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-05-06-flaske8afb7e6b182e695b0e68dae/</guid><description/></item><item><title>实现QGraphicsItem拖拽功能</title><link>https://blog.perillaroc.wang/post/2015/2015-05-06-e5ae9ee78eb0qgraphicsiteme68b96e68bbde58a9fe883bd/</link><pubDate>Wed, 06 May 2015 19:18:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-05-06-e5ae9ee78eb0qgraphicsiteme68b96e68bbde58a9fe883bd/</guid><description/></item><item><title>2015年 ecmwf 的 GRIB API 培训教材</title><link>https://blog.perillaroc.wang/post/2015/2015-04-28-2015e5b9b4-ecmwf-e79a84-grib-api-e59fb9e8aeade69599e69d90/</link><pubDate>Tue, 28 Apr 2015 13:05:54 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-04-28-2015e5b9b4-ecmwf-e79a84-grib-api-e59fb9e8aeade69599e69d90/</guid><description/></item><item><title>D3.js学习笔记：绘制树形图</title><link>https://blog.perillaroc.wang/post/2015/2015-04-25-d3-notebook-draw-tree-map/</link><pubDate>Sat, 25 Apr 2015 15:52:02 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-04-25-d3-notebook-draw-tree-map/</guid><description>&lt;p&gt;业务运行系统按如下方式组织：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ww2.sinaimg.cn/mw690/4afdac38jw1erdi27ugadj20gr0io413.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我只关心结构，不关心颜色等其它信息。上图是一个明显的树形结构，可以利用 D3 的 tree 模块在网页中现实。&lt;br&gt;
D3 Tree Layout 参考：&lt;/p&gt;
&lt;p&gt;《&lt;a href="https://github.com/mbostock/d3/wiki/Tree-Layout"&gt;Tree Layout&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="数据准备"&gt;数据准备&lt;/h2&gt;
&lt;p&gt;需要json表示的树对象，形如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;flare&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;children&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;analytics&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;children&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;cluster&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;children&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;AgglomerativeCluster&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;size&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3938&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;CommunityStructure&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;size&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3812&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;MergeEdge&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;size&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;743&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;graph&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;children&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;BetweennessCentrality&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;size&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3534&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;LinkDistance&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;size&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5731&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;递归定义结构，其中 name 表示节点名，children 表示子节点数组，其它字段任意。&lt;/p&gt;
&lt;p&gt;D3 的 Tree Layout 文档中给出一些常用的字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parent&lt;/code&gt;：父节点，根结点为null&lt;/li&gt;
&lt;li&gt;&lt;code&gt;children&lt;/code&gt;：子节点，叶子节点为null&lt;/li&gt;
&lt;li&gt;&lt;code&gt;depth&lt;/code&gt;：节点深度，根结点从0开始&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;：节点的 x 坐标&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt;：节点的 y 坐标&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;之前已经准备好节点树对象的 json 数据，但需要修改。D3示例中叶子节点没有 children 属性，但我生成的 json 数据中叶子节点有值为空数组的 children 属性。需要在调用api获取数据后，删掉叶子节点中的 children 属性。&lt;/p&gt;</description></item><item><title>ecFlow学习笔记01 —— 编译ecFlow</title><link>https://blog.perillaroc.wang/post/2015/2015-04-16-ecflow-notebook-build-ecflow/</link><pubDate>Thu, 16 Apr 2015 18:36:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-04-16-ecflow-notebook-build-ecflow/</guid><description>&lt;h2 id="编译说明v3"&gt;编译说明v3&lt;/h2&gt;
&lt;p&gt;本文内容已不适用于最新的ecFlow版本，可以参考&lt;a href="https://github.com/perillaroc/ecflow-docker"&gt;perillaroc/ecflow-docker&lt;/a&gt;中的编译方法。&lt;/p&gt;
&lt;h2 id="编译说明v2"&gt;编译说明v2&lt;/h2&gt;
&lt;p&gt;在 Ubuntu 中安装 ecFlow 4.0.9，详细安装说明参见官方文档：&lt;br&gt;
&lt;a href="https://software.ecmwf.int/wiki/display/ECFLOW/Installation"&gt;https://software.ecmwf.int/wiki/display/ECFLOW/Installation&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="依赖包"&gt;依赖包&lt;/h3&gt;
&lt;p&gt;编译 ecFlow 需要的依赖软件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cmake&lt;/li&gt;
&lt;li&gt;g++&lt;/li&gt;
&lt;li&gt;python&lt;/li&gt;
&lt;li&gt;Xlib X11 XMotif&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="建立编译环境"&gt;建立编译环境&lt;/h3&gt;
&lt;p&gt;ecFlow 需要两个安装包：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ecFlow-4.0.9-Source.tar.gz&lt;/li&gt;
&lt;li&gt;boost_1_53_0.tar.gz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一个从 ecFlow 的官网上下载，第二个可以从 boost 库的官方网站下载。&lt;br&gt;
创建编译需要的目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow$ mkdir ecflow_build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;拷贝上面两个压缩包到该目录，并解压&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;boost_1_53_0.tar.gz ecFlow-4.0.9-Source.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ tar zxf ecFlow-4.0.9-Source.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ tar zxf boost_1_53_0.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到两个目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ ls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;boost_1_53_0 boost_1_53_0.tar.gz ecFlow-4.0.9-Source ecFlow-4.0.9-Source.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建两个环境变量，某些脚本需要用到&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ export WK&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/windroc/app/ecmwf/ecflow/ecflow_build/ecFlow-4.0.9-Source
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ export BOOST_ROOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/windroc/app/ecmwf/ecflow/ecflow_build/boost_1_53_0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="编译boost"&gt;编译BOOST&lt;/h3&gt;
&lt;p&gt;Boost 使用 bjam 编译 boost 库。我们需要首先编译bjam&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build$ cd $BOOST_ROOT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;windroc@ubuntu:~/app/ecmwf/ecflow/ecflow_build/boost_1_53_0$ ./bootstrap.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ecFlow 使用 boost 中一些需要编译的库。下面的脚本将编译这些需要的库，包括debug和release版本，并根据你的平台配置boost编译。&lt;/p&gt;</description></item><item><title>AIX下编译GRIB API 1.13.0</title><link>https://blog.perillaroc.wang/post/2015/2015-04-02-grib-api-notebook-build-v1-13-0-on-aix/</link><pubDate>Thu, 02 Apr 2015 10:24:38 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-04-02-grib-api-notebook-build-v1-13-0-on-aix/</guid><description>&lt;h2 id="环境"&gt;环境&lt;/h2&gt;
&lt;p&gt;GRIB API：1.13.0&lt;br&gt;
AIX：7.1&lt;br&gt;
xlc：12.1&lt;/p&gt;
&lt;h2 id="修改configure文件"&gt;修改configure文件&lt;/h2&gt;
&lt;p&gt;在xlc中使用gcc的&lt;code&gt;-pendantic&lt;/code&gt;参数会有编译错误，没有找到对应的xlc选项，连同&lt;code&gt;-Wall&lt;/code&gt;选项一起删掉，这样就没有那么多的编译警告了。&lt;/p&gt;
&lt;p&gt;只需要修改两个地方，下面是diff的结果&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ diff configure configure.orig
19785c19785
&amp;lt; CFLAGS=&amp;#34; &amp;#34;
---
&amp;gt; CFLAGS=&amp;#34;-pedantic -Wall&amp;#34;
19808c19808
&amp;lt; WARN_PEDANTIC=&amp;#34; &amp;#34;
---
&amp;gt; WARN_PEDANTIC=&amp;#34;-pedantic -Wall&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="编译"&gt;编译&lt;/h2&gt;
&lt;p&gt;配置jasper库的位置（或者openjpeg）、prefix安装目录前缀，并指定使用xlc编译器（configure默认识别出来的gcc在AIX下没法用）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --with-jasper&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/cma/u/app/jasper --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SOME_PATH CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlc CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后make、make install，就可以使用。&lt;/p&gt;</description></item><item><title>Celery入门</title><link>https://blog.perillaroc.wang/post/2015/2015-02-27-celerye585a5e997a8/</link><pubDate>Fri, 27 Feb 2015 16:14:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-27-celerye585a5e997a8/</guid><description/></item><item><title>Fabric入门</title><link>https://blog.perillaroc.wang/post/2015/2015-02-26-fabrice585a5e997a8/</link><pubDate>Thu, 26 Feb 2015 16:06:46 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-26-fabrice585a5e997a8/</guid><description/></item><item><title>Docker中使用Apache Kafka</title><link>https://blog.perillaroc.wang/post/2015/2015-02-25-dockere4b8ade4bdbfe794a8apache-kafka/</link><pubDate>Wed, 25 Feb 2015 15:39:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-25-dockere4b8ade4bdbfe794a8apache-kafka/</guid><description/></item><item><title>Docker入门</title><link>https://blog.perillaroc.wang/post/2015/2015-02-25-dockere585a5e997a8/</link><pubDate>Wed, 25 Feb 2015 13:27:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-25-dockere585a5e997a8/</guid><description/></item><item><title>使用Docker封装Redis服务</title><link>https://blog.perillaroc.wang/post/2015/2015-02-11-e4bdbfe794a8dockere5b081e8a385redise69c8de58aa1/</link><pubDate>Wed, 11 Feb 2015 23:33:26 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-11-e4bdbfe794a8dockere5b081e8a385redise69c8de58aa1/</guid><description/></item><item><title>Windows中通过Boot2Docker使用Docker</title><link>https://blog.perillaroc.wang/post/2015/2015-02-10-windowse4b8ade9809ae8bf87boot2dockere4bdbfe794a8docker/</link><pubDate>Tue, 10 Feb 2015 13:21:15 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-10-windowse4b8ade9809ae8bf87boot2dockere4bdbfe794a8docker/</guid><description/></item><item><title>SQLAlchemy中使用同一模型映射多个表</title><link>https://blog.perillaroc.wang/post/2015/2015-02-04-sqlalchemy-use-one-model-to-map-multi-tables/</link><pubDate>Wed, 04 Feb 2015 19:14:59 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-04-sqlalchemy-use-one-model-to-map-multi-tables/</guid><description>&lt;p&gt;为了查询效率，将单一表根据某种条件分成多张表，每个表的结构完全相同，只有表名不同。
已经在SQLAlchemy中定义一个类Record表示表结构，在不同条件下需要修改该类对应的表名。&lt;/p&gt;
&lt;p&gt;其实，应该使用更合适的“分表”技术，不需要如此麻烦。但现在我还没研究过“分表”，只好选择这种不优雅的方式。&lt;/p&gt;
&lt;p&gt;下面介绍我试过的两种方法，可以实现修改表名。&lt;/p&gt;
&lt;h2 id="动态修改表名"&gt;动态修改表名&lt;/h2&gt;
&lt;p&gt;这种方式适合select查询，其它未测试过。&lt;/p&gt;
&lt;p&gt;定义Record类时，定义默认表的名称&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Record&lt;/span&gt;(Model):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; __tablename__ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;record_nwp_cma20n03&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用Record类时，提前修改表名&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Record&lt;span style="color:#f92672"&gt;.&lt;/span&gt;__table__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;record_&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;repo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后的查询都会在新指定的表中查找。&lt;/p&gt;
&lt;p&gt;另一个示例&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Session()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Record&lt;span style="color:#f92672"&gt;.&lt;/span&gt;__table__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;record_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{repo_name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(repo_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;nwp_cma20n03&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;query(Record)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print query
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Record&lt;span style="color:#f92672"&gt;.&lt;/span&gt;__table__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;record_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{repo_name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(repo_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;nwp_qu_cma20n03&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;query(Record)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print query
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SELECT ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FROM record_nwp_cma20n03
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SELECT ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FROM record_nwp_qu_cma20n03
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到，两次查询的表名确实变了。&lt;/p&gt;
&lt;h3 id="局限"&gt;局限&lt;/h3&gt;
&lt;p&gt;但该方法并不总能成功，当我用如下的语句插入数据时，表名仅在第一次设置时有效，之后设置均没有效果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; message &lt;span style="color:#f92672"&gt;in&lt;/span&gt; consumer:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; table_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;record_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{repo_name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(repo_name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;message[&lt;span style="color:#e6db74"&gt;&amp;#39;repo&amp;#39;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Record&lt;span style="color:#f92672"&gt;.&lt;/span&gt;__table__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; table_name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a_record &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Record()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; session&lt;span style="color:#f92672"&gt;.&lt;/span&gt;add(a_record)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体原因我不清楚，可能每个类只能对应一个映射关系，使用session.query时可以动态更新tablename，但使用session.add时只能使用第一次绑定的映射关系。&lt;/p&gt;
&lt;p&gt;如果需要映射多个表，最好为每个表指定一个映射类。&lt;/p&gt;
&lt;p&gt;SQLAlchemy的文档中有这种情况的详细描述，
参见《&lt;a href="//docs.sqlalchemy.org/en/rel_0_9/orm/nonstandard_mappings.html#multiple-mappers-for-one-class"&gt;Multiple Mappers for One Class&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="同一个模型映射多个表"&gt;同一个模型映射多个表&lt;/h2&gt;
&lt;p&gt;上面的文档中提到一种映射多个相同表的方法，参见《&lt;a href="https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/EntityName"&gt;Entity Name&lt;/a&gt;》。&lt;/p&gt;</description></item><item><title>MongoDB简单使用</title><link>https://blog.perillaroc.wang/post/2015/2015-02-03-mongodbe7ae80e58d95e4bdbfe794a8/</link><pubDate>Tue, 03 Feb 2015 20:50:46 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-03-mongodbe7ae80e58d95e4bdbfe794a8/</guid><description/></item><item><title>解决Vagrant中VirtualBox Guest Additions版本不匹配问题</title><link>https://blog.perillaroc.wang/post/2015/2015-02-02-e8a7a3e586b3vagrante4b8advirtualbox-guest-additionse78988e69cace4b88de58cb9e9858de997aee9a298/</link><pubDate>Mon, 02 Feb 2015 09:49:02 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-02-e8a7a3e586b3vagrante4b8advirtualbox-guest-additionse78988e69cace4b88de58cb9e9858de997aee9a298/</guid><description/></item><item><title>为AngularJS添加Ajax载入动画</title><link>https://blog.perillaroc.wang/post/2015/2015-02-02-e4b8baangularjse6b7bbe58aa0ajaxe8bdbde585a5e58aa8e794bb/</link><pubDate>Mon, 02 Feb 2015 09:23:02 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-02-e4b8baangularjse6b7bbe58aa0ajaxe8bdbde585a5e58aa8e794bb/</guid><description/></item><item><title>开始使用Python Requests</title><link>https://blog.perillaroc.wang/post/2015/2015-02-02-e5bc80e5a78be4bdbfe794a8python-requests/</link><pubDate>Mon, 02 Feb 2015 09:20:51 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-02-02-e5bc80e5a78be4bdbfe794a8python-requests/</guid><description>&lt;h2&gt;&lt;/h2&gt;</description></item><item><title>D3.js学习笔记：绘制日历（2）</title><link>https://blog.perillaroc.wang/post/2015/2015-01-22-d3-notebook-draw-calendar-2nd/</link><pubDate>Thu, 22 Jan 2015 20:15:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-01-22-d3-notebook-draw-calendar-2nd/</guid><description>&lt;p&gt;之前一篇博文《[D3.js学习笔记：绘制日历](https://blog.perillaroc.wang/post/2015/2015-01-05-d3-notebook-draw-calendar/》介绍我如何仿制github全年日历，本文介绍我仿制月份日历。示例截图：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ww1.sinaimg.cn/large/4afdac38gw1eoijld01w7j20lx0e8jtw.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;我用一个中午的时间仿制上面的网页，截图如下：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ww1.sinaimg.cn/large/4afdac38gw1eoijlchahuj20qi0gc0wb.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;大致模拟出样例的表现形式，细节有待进一步处理。&lt;/p&gt;
&lt;h2 id="分析"&gt;分析&lt;/h2&gt;
&lt;p&gt;时间范围从某月1号所在星期的星期一开始，连续六周，共42天。&lt;/p&gt;
&lt;p&gt;数据分两种，上面的矩形框每个过去的日期都有，下面的矩形框只有特定的日期才有。其实这两种数据可以看做是同一个形式，只不过一种是连续时间序列，另一种只有离散数据点，采用相同的方式处理。&lt;/p&gt;
&lt;p&gt;我选择使用rect矩形来绘出各个元素：日期网格、日期标签、两个数据标签。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;h3 id="数据准备"&gt;数据准备&lt;/h3&gt;
&lt;p&gt;使用D3提供的函数来生成日期序列。&lt;/p&gt;
&lt;p&gt;假定提供某个月份的任意一个日期&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;query_day&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当前月份的1号所在星期的星期一&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;start_day&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;monday&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;month&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;query_day&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;6周后的周日&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end_day&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;start_day&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成日期序列&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end_day&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;start_day&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="坐标"&gt;坐标&lt;/h3&gt;
&lt;p&gt;javascript中默认一周的第一天是周日，而我们平时以周一为第一天，所以在计算纵坐标时要计算当前日期前一天所在的周数。&lt;br&gt;
六周的序列&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;week_range&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;weeks&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;start_day&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;), &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;end_day&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;纵坐标&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y_week_scale&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;scale&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ordinal&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;domain&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;week_range&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;rangeBands&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;day_grid_groups&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;rect&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;day&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;y_week_scale&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;week&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;)) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cell_height&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;横坐标也需要计算当前日期的前一天。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x_format&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%w&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;day_grid_groups&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;rect&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;day&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;x_format&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cell_width&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="绘制"&gt;绘制&lt;/h3&gt;
&lt;p&gt;具体绘制方法与之前博文相似，只需要分别绘制各个矩形即可，不再列出代码。&lt;/p&gt;</description></item><item><title>Flask配置管理</title><link>https://blog.perillaroc.wang/post/2015/2015-01-21-flaske9858de7bdaee7aea1e79086/</link><pubDate>Wed, 21 Jan 2015 19:51:57 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-01-21-flaske9858de7bdaee7aea1e79086/</guid><description>&lt;p style="text-align: right;"&gt;</description></item><item><title>ZeroMQ使用小记</title><link>https://blog.perillaroc.wang/post/2015/2015-01-20-zeromqe4bdbfe794a8e5b08fe8aeb0/</link><pubDate>Tue, 20 Jan 2015 23:07:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-01-20-zeromqe4bdbfe794a8e5b08fe8aeb0/</guid><description/></item><item><title>2014个人总结</title><link>https://blog.perillaroc.wang/post/2015/2015-01-08-2014-summary/</link><pubDate>Thu, 08 Jan 2015 14:09:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-01-08-2014-summary/</guid><description>&lt;p&gt;2015年已经过去一周，去年12月份以来单位就在做2014年总结和2015年计划，没有繁杂的任务，可惜这几周我还有些私人事情需要处理，一直没有静下心来好好回顾下我的2014年——参加工作的第二年。今天晚上我还是找出一些时间简单写些文字，包括许久没有写的心情文字。已经过去的2014年到底留下了什么，我真得好好看看。&lt;/p&gt;
&lt;h2 id="写代码的2014年"&gt;写代码的2014年&lt;/h2&gt;
&lt;p&gt;一张图描述我的码农2014年&lt;/p&gt;
&lt;figure&gt;&lt;img src="http://ww1.sinaimg.cn/large/4afdac38gw1eo1cipd0qaj20ph09wn1d.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;我的GitHub一年活动统计图，包括单位我参与的部分项目和所有的个人项目。&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;从图中可以看到，我的2014年明显集中到三个时间段：2月下旬至4月上旬、8月中下旬至9月、12月，分别对应不同的兴趣关注点，这就暴露我目前最大的一个问题：&lt;/p&gt;
&lt;h2 id="频繁变化的兴趣"&gt;频繁变化的兴趣&lt;/h2&gt;
&lt;p&gt;写代码高峰期的关注点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;2月至4月：&lt;span class="author"&gt;&lt;a class="url fn" style="color: #4183c4;" href="https://github.com/perillaroc" rel="author"&gt;perillaroc&lt;/a&gt;&lt;/span&gt;&lt;span class="path-divider"&gt;/&lt;/span&gt;&lt;strong&gt;&lt;a class="js-current-repository" style="color: #4183c4;" href="https://github.com/perillaroc/weibo-analytics" data-pjax="#js-repo-pjax-container"&gt;weibo-analytics&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;8月至9月：&lt;span class="author"&gt;&lt;a class="url fn" style="color: #4183c4;" href="https://github.com/perillaroc" rel="author"&gt;perillaroc&lt;/a&gt;&lt;/span&gt;&lt;span class="path-divider"&gt;/&lt;/span&gt;&lt;strong&gt;&lt;a class="js-current-repository" style="color: #4183c4;" href="https://github.com/perillaroc/nwpc-grapes-meso-script" data-pjax="#js-repo-pjax-container"&gt;nwpc-grapes-meso-script&lt;/a&gt;     &lt;strong&gt;&lt;span class="author"&gt;&lt;a class="url fn" style="color: #4183c4;" href="https://github.com/perillaroc" rel="author"&gt;perillaroc&lt;/a&gt;&lt;/span&gt;&lt;span class="path-divider"&gt;/&lt;/span&gt;&lt;/strong&gt;&lt;a class="js-current-repository" style="color: #4183c4;" href="https://github.com/perillaroc/porter" data-pjax="#js-repo-pjax-container"&gt;porter&lt;/a&gt;     &lt;strong&gt;&lt;span class="author"&gt;&lt;a class="url fn" style="color: #4183c4;" href="https://github.com/perillaroc" rel="author"&gt;perillaroc&lt;/a&gt;&lt;/span&gt;&lt;span class="path-divider"&gt;/&lt;/span&gt;&lt;/strong&gt;&lt;a class="js-current-repository" style="color: #4183c4;" href="https://github.com/perillaroc/takler" data-pjax="#js-repo-pjax-container"&gt;takler&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;12月：&lt;span class="author"&gt;&lt;a class="url fn" style="color: #4183c4;" href="https://github.com/perillaroc" rel="author"&gt;perillaroc&lt;/a&gt;&lt;/span&gt;&lt;span class="path-divider"&gt;/&lt;/span&gt;**&lt;a class="js-current-repository" style="color: #4183c4;" href="https://github.com/perillaroc/sms-log-collector" data-pjax="#js-repo-pjax-container"&gt;sms-log-collector&lt;/a&gt;   &lt;strong&gt;&lt;span class="author"&gt;&lt;a class="url fn" style="color: #4183c4;" href="https://github.com/perillaroc" rel="author"&gt;perillaroc&lt;/a&gt;&lt;/span&gt;&lt;span class="path-divider"&gt;/&lt;/span&gt;&lt;/strong&gt;&lt;a class="js-current-repository" style="color: #4183c4;" href="https://github.com/perillaroc/sms-log-reporter" data-pjax="#js-repo-pjax-container"&gt;sms-log-reporter&lt;/a&gt; **&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="weibo-analytics"&gt;weibo-analytics&lt;/h3&gt;
&lt;p&gt;一个做了好多年都没有实际应用的微博应用。最早在2012年自学PHP的时候练手，后来中断了。2013年关注点转向Python，在学习flask时改写首页后中断。2014年2月份时兴趣再一次转向Python，拾起这个小项目，完成了几个简单的功能，也部署到SAE上。但没有继续完善，没有参与审核，只能我自己用。总之，还是一个烂尾工程。&lt;/p&gt;
&lt;figure style="width: 910px" class="wp-caption alignnone"&gt;&lt;img src="http://ww1.sinaimg.cn/large/4afdac38gw1eo1dkxdm3sj20pa043glh.jpg" alt="" width="910" height="147" /&gt;&lt;figcaption class="wp-caption-text"&gt;weibo-analytics每周提交数统计，提交峰值位于三月初。图片来自GitHub。&lt;/figcaption&gt;&lt;/figure&gt; 
从2012年每天都发微博，到现在一个月才发个位数的微博，做这个项目的动力已经完全消失。也许我该找个可以替代新浪微博的类型社交平台，就可以继续这个项目了。
&lt;p style="text-align: right;"&gt;
 今天没办法继续写了，还是明天吧。2015年1月7日
&lt;/p&gt;
&lt;figure style="width: 830px" class="wp-caption alignnone"&gt;&lt;img src="http://ww4.sinaimg.cn/large/4afdac38gw1eo1dkxpal7j20n20clt8x.jpg" alt="" width="830" height="453" /&gt;&lt;figcaption class="wp-caption-text"&gt;2014年我的新浪微博统计，发微博数逐月下滑，11月甚至只有3条微薄。图片来自我的微博小应用。&lt;/figcaption&gt;&lt;/figure&gt; 
这个项目中，总算有些眉目如何使用Flask开发简单的应用。但登陆模块Flask-Security依旧没有吃透，另外还应该看看Flask的源码。 
五一长假过后，一直没有从放假的状态走出来，没有强迫自己写代码，当时晚上下班后大半时间都在玩游戏，从活动图中看得很明显。5月初写第一季度工作总结报告，7月初写年中工作总结报告，发现自己半年没有做什么事。这期间才开始利用工作和业余时间继续写代码，而这时候我的关注点又有新的变化。
&lt;h3 id="grapes-meso-script"&gt;grapes-meso-script&lt;/h3&gt;
&lt;p&gt;我觉得自己做与工作无关的项目没有实质利益，一次组会上意识到我应该学习如何运行数值预报模式。我开始手动运行GRAPES MESOV3.3模式，从最开始的跑模式源码提供的脚本，到自己编写按模块运行的shell脚本，到最后尝试使用Python改写脚本。期间写了一系列博文，即&lt;span style="color: #555555;"&gt;GRAPES MESO模式学习笔记01-08。&lt;/span&gt;&lt;/p&gt;
&lt;figure style="width: 1128px" class="wp-caption alignnone"&gt;&lt;img src="http://ww3.sinaimg.cn/large/4afdac38gw1eo1u8tuuhuj20vc055mx1.jpg" alt="" width="1128" height="185" /&gt;&lt;figcaption class="wp-caption-text"&gt;2014年grapes-meso-script每周提交分布图，图片来自GitHub。7月初完成shell版本的开发，7月末完成Python脚本的分解，8月末完成共有参数的提取。9月更新主要修改测试数据来源和日期。&lt;/figcaption&gt;&lt;/figure&gt; 
但我只停留在规划路线图中的第四步——提取公共变量到配置文件，后续真正有价值的研究工作没有进行下去，也就没能将规划路线图升级为技术研发路线图。停留在代码阶段属于在做重复劳动，缺乏核心价值。什么能体现自己的不可替代？可不是写代码。 
未来我们可能会使用ecFlow替代SMS，这是将独立脚本升级成可复用模块组件的转折点，今年可能会继续这方面的研究工作，重点完成规划路下图尚未完成的工作。 
8月初我旁听单位一次新员工培训，一位前辈讲解数据转码工具的使用。当时我的工作项目也有一位前辈完成了一个数据转码工具。我的关注点转向研究GRADS的数据格式，也就有下面的这个小项目。
&lt;h3 id="porterperillaroc-data-converter"&gt;porter：perillaroc-data-converter&lt;/h3&gt;
&lt;p&gt;结合两位前辈的转码工具源码，我学习GRADS二进制数据格式，和Micaps第四类数据格式，半个月时间，写了一个将GrADS格式转为Micaps第四类数据格式的实验程序，又是一个半成品都不算，仅仅是实验性质的小项目。同时写了两篇博文描述GrADS数据格式及其解析，《&lt;span style="font-weight: 600; color: #555555;"&gt;&lt;a class="row-title" style="color: #0074a2;" title="编辑“GrADS格点数据格式”" href="//windrocblog.sinaapp.com/wp-admin/post.php?post=1459&amp;action=edit"&gt;GrADS格点数据格式&lt;/a&gt;&lt;/span&gt;》和《&lt;span style="font-weight: 600; color: #555555;"&gt;&lt;a class="row-title" style="color: #0074a2;" title="编辑“GrADS格点数据文件解析”" href="//windrocblog.sinaapp.com/wp-admin/post.php?post=1470&amp;action=edit"&gt;GrADS格点数据文件解析&lt;/a&gt;&lt;/span&gt;》。&lt;/p&gt;</description></item><item><title>D3.js学习笔记：绘制热点图</title><link>https://blog.perillaroc.wang/post/2015/2015-01-06-d3-notebook-draw-heatmap/</link><pubDate>Tue, 06 Jan 2015 10:15:04 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-01-06-d3-notebook-draw-heatmap/</guid><description>&lt;h2 id="介绍"&gt;介绍&lt;/h2&gt;
&lt;p&gt;热力图用矩阵表示数据关系，用颜色表示数值。例如：&lt;br&gt;
《&lt;a href="//bl.ocks.org/tjdecke/5558084"&gt;Day / Hour Heatmap&lt;/a&gt;》&lt;/p&gt;
&lt;figure style="width: 948px" class="wp-caption alignnone"&gt;&lt;img src="http://ww2.sinaimg.cn/large/4afdac38gw1enyllu7jjqj20qc09z76p.jpg" alt="" width="948" height="359" /&gt;&lt;figcaption class="wp-caption-text"&gt;显示同时在线的用户数量&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;上图受下面项目的启发而绘制。&lt;/p&gt;
&lt;p&gt;《&lt;a href="//www.trulia.com/vis/tru247/"&gt;House Hunting All Day, Every Day&lt;/a&gt;》&lt;/p&gt;
&lt;img class="alignnone" src="http://ww4.sinaimg.cn/large/4afdac38gw1enylluq96oj20r70lj432.jpg" alt="" width="979" height="775" /&gt; 
该项目使用d3.js，但没有全部使用svg，网格用div绘制。第一个项目中，作者则完全使用svg绘图。所以我主要参照第一个项目实现热力图。
&lt;h2 id="需求"&gt;需求&lt;/h2&gt;
&lt;p&gt;显示每个项目每小时的数据。用颜色表示数据大小。横坐标为小时，纵坐标为项目。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;h3 id="输入数据"&gt;输入数据&lt;/h3&gt;
&lt;p&gt;图形为矩阵形式，可以考虑用矩阵作为输入数据。但考虑到以下两点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每行都是同一事物在不同时间段的数据，应该将这些数据放到一起便于交互查询。&lt;/li&gt;
&lt;li&gt;d3的数据机制最适合处理数组，比矩阵更简单直观。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;输入数据形如二维数组形式（还有其他附属变量），在数据处理阶段时，将二维数组变为一维数组。
api返回数据：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;row&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;values&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;645&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;567&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;values&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;355&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	 ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与上一篇博文类似，需要将数据扩展到0-24小时范围上。具体方法不再描述，详情请参看上一篇博文。&lt;/p&gt;
&lt;h3 id="数据处理"&gt;数据处理&lt;/h3&gt;
&lt;p&gt;将二维数组转变为一维数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;heat_map_data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new_value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;grid_data&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;row_name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;heat_map_data&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;row_element&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;row_index&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;row_array&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;row&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;row_element&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;chart_values&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;index&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;array&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;grid_data&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;row_index&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;row_name&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;push&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="矩阵网格"&gt;矩阵网格&lt;/h3&gt;
&lt;h4 id="横坐标"&gt;横坐标&lt;/h4&gt;
&lt;p&gt;横坐标是小时&lt;/p&gt;</description></item><item><title>D3.js学习笔记：绘制日历</title><link>https://blog.perillaroc.wang/post/2015/2015-01-05-d3-notebook-draw-calendar/</link><pubDate>Mon, 05 Jan 2015 10:43:43 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2015/2015-01-05-d3-notebook-draw-calendar/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;日历是按日期分布的数据最直观的可视化形式。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;时间属性可以和人类日历对应，缤纷为年、月、周、日、小时等多个等级。因此，采用日历表达时间属性，和我们识别时间的习惯相符合。————《数据可视化》 陈为等&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;书中给出一个使用d3.js绘制的例子&lt;/p&gt;
&lt;figure&gt;&lt;img src="http://ww2.sinaimg.cn/large/4afdac38gw1enyd6a443sj20q50bmadz.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;2007年至2009年美国道琼斯股票指数，红色表示下跌，绿色表示上涨。图片来源：//bl.ocks.org/mbostock/4063318&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;代码请参见d3.js作者的博客《&lt;a href="//bl.ocks.org/mbostock/4063318"&gt;Calendar View&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;GitHub也使用日历来显示用户的活跃度。下图是我2014年的活跃度。&lt;/p&gt;
&lt;figure&gt;&lt;img src="http://ww3.sinaimg.cn/large/4afdac38gw1enyd1jtmzrj20ph09wack.jpg"&gt;&lt;figcaption&gt;
			&lt;h4&gt;2014年我在github的活动统计图。图片来源：https://github.com/perillaroc&lt;/h4&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;参考上述两个示例，我使用d3.js绘制日历图。&lt;/p&gt;
&lt;h2 id="实现"&gt;实现&lt;/h2&gt;
&lt;p&gt;用一个例子来说明绘制日历的过程。&lt;/p&gt;
&lt;h3 id="需求"&gt;需求&lt;/h3&gt;
&lt;p&gt;与GitHub类似，展示从当前日期之前一年内每天的数据，用颜色表示数值的大小，颜色越浅，数目越小，颜色越深，数目越大。没有数据则用灰色背景表示。&lt;br&gt;
纵轴表示星期，横轴表示周数。与GitHub不同，我设定起始日期始终是一年前的周日。&lt;/p&gt;
&lt;h3 id="数据准备"&gt;数据准备&lt;/h3&gt;
&lt;h4 id="输入数据"&gt;输入数据&lt;/h4&gt;
&lt;p&gt;当前日期&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end_date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;end_date
Mon Jan 05 2015 09:24:13 GMT+0800 (中国标准时间)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当前能获得的日期数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;collect_date_value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-01&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-02&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-03&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-04&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-05&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-06&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;2014-10-07&amp;#39;&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;日期格式：&lt;br&gt;
使用&lt;code&gt;d3.time.format&lt;/code&gt;定义日期格式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;date_format&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;%Y-%m-%d&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;date_format(new Date())
&amp;#34;2015-01-05&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="数据处理"&gt;数据处理&lt;/h4&gt;
&lt;h5 id="一年前的周日"&gt;一年前的周日&lt;/h5&gt;
&lt;p&gt;d3提供丰富的日期操作函数，使用&lt;code&gt;d3.time.week&lt;/code&gt;返回之前最近的周日。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Date();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;setFullYear&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;end_date&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getFullYear&lt;/span&gt;()&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;week&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;start_date
Sun Jan 05 2014 00:00:00 GMT+0800 (中国标准时间)
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="日期序列"&gt;日期序列&lt;/h5&gt;
&lt;p&gt;使用&lt;code&gt;d3.time.days&lt;/code&gt;生成日期序列&lt;/p&gt;</description></item><item><title>解决大量更新记录时MySQL Error 2013</title><link>https://blog.perillaroc.wang/post/2014/2014-12-29-e8a7a3e586b3e5a4a7e9878fe69bb4e696b0e8aeb0e5bd95e697b6mysql-error-2013/</link><pubDate>Mon, 29 Dec 2014 13:40:15 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-12-29-e8a7a3e586b3e5a4a7e9878fe69bb4e696b0e8aeb0e5bd95e697b6mysql-error-2013/</guid><description/></item><item><title>Flask自定义json编码器</title><link>https://blog.perillaroc.wang/post/2014/2014-12-29-flaske887aae5ae9ae4b989jsone7bc96e7a081e599a8/</link><pubDate>Mon, 29 Dec 2014 13:14:51 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-12-29-flaske887aae5ae9ae4b989jsone7bc96e7a081e599a8/</guid><description/></item><item><title>D3.js学习笔记：绘制简单的时间轴</title><link>https://blog.perillaroc.wang/post/2014/2014-12-23-d3-notebook-draw-simple-timeline/</link><pubDate>Tue, 23 Dec 2014 10:05:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-12-23-d3-notebook-draw-simple-timeline/</guid><description>&lt;p&gt;最近研究按时间排序的事件序列，说的直接点就是日志，想用时间线来表示状态发生变化的各个时间点。考虑用D3实现，下面是我尝试绘制时间线的记录。&lt;/p&gt;
&lt;h2 id="时间序列"&gt;时间序列&lt;/h2&gt;
&lt;p&gt;确定起止时间点。因为要使用d3的比例尺，所以不需要生成时间序列，只需要给出时间范围即可。我只关注某一天的事件，时间范围就是从当前的0时到第二天的0时。&lt;/p&gt;
&lt;p&gt;利用d3的时间间隔函数可以生成0时的date对象。&lt;code&gt;d3.time.day&lt;/code&gt;返回当天0时的对象，&lt;code&gt;d3.time.day.offset&lt;/code&gt;返回隔几天而时间不变的对象。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;scope&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;date&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end_date&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;day&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;offset&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;例如：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;scope.date = Mon Dec 15 2014 08:00:00 GMT+0800 
start_date = Mon Dec 15 2014 00:00:00 GMT+0800 
end_date = Tue Dec 16 2014 00:00:00 GMT+0800
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="时间比例尺"&gt;时间比例尺&lt;/h2&gt;
&lt;p&gt;显示时间点确定在时间线上的位置，所以需要将时间范围映射到时间线的长度中。利用d3为时间准备的比例尺&lt;code&gt;d3.time.scale&lt;/code&gt;可以实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time_line_scale&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;scale&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;domain&lt;/span&gt;([&lt;span style="color:#a6e22e"&gt;start_date&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;end_date&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;range&lt;/span&gt;([&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;time_line_axis_width&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;例：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt; time_line_axis_width 
700
&amp;gt; time_line_scale(new Date(&amp;#34;Mon Dec 15 2014 12:00:00 GMT+0800&amp;#34;) 
350
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;12点映射为长度的一半。&lt;/p&gt;
&lt;h2 id="时间轴坐标"&gt;时间轴坐标&lt;/h2&gt;
&lt;p&gt;d3提供封装好的坐标函数&lt;code&gt;d3.svg.axis&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time_line_axis&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;svg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;axis&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;scale&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;time_line_scale&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;orient&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;bottom&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="绘制坐标轴"&gt;绘制坐标轴&lt;/h2&gt;
&lt;p&gt;将目前的坐标绘制到屏幕中，这里多写点儿代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;svg&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;d3&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;select&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]).&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;svg&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;,&lt;span style="color:#e6db74"&gt;&amp;#39;YlGn&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;width&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;svg_attr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;width&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;px&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;height&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;svg_attr&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;height&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;px&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;axis_group&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;svg&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;append&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;g&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;attr&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;time-line axis&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;time_line_axis&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;得到的效果：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ww1.sinaimg.cn/mw690/4afdac38gw1enijnx5q8pj20kb00udfy.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>AIX下编译Redis</title><link>https://blog.perillaroc.wang/post/2014/2014-08-29-build-redis-on-aix/</link><pubDate>Fri, 29 Aug 2014 10:39:23 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-29-build-redis-on-aix/</guid><description>&lt;h2 id="基本环境"&gt;基本环境&lt;/h2&gt;
&lt;p&gt;AIX：7.1&lt;/p&gt;
&lt;p&gt;编译器xlc：12.1&lt;/p&gt;
&lt;p&gt;Resia源码：2.8.13&lt;/p&gt;
&lt;p&gt;直接编译肯定无法通过，xlc与gcc的编译选项不能完全通用，需要修改Makefile和一些源代码文件。&lt;/p&gt;
&lt;h2 id="依赖库文件修改"&gt;依赖库文件修改&lt;/h2&gt;
&lt;h3 id="hiredis"&gt;hiredis&lt;/h3&gt;
&lt;p&gt;在src/Makefile中增加宏定义，主要是为了使用socket（？）。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-D__HIREDIS_FMACRO_H -D_BSD_SOURCE -DAF_LOCAL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;AF_UNIX
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改DEBUG选项，去掉&lt;code&gt;-ggdb&lt;/code&gt;，这项会被xlc解析出&lt;code&gt;-b&lt;/code&gt;选项，可能会出现干扰。修改链接选项，将&lt;code&gt;-shared&lt;/code&gt;改为&lt;code&gt;-qmkshrobj&lt;/code&gt;。同时还需要修改&lt;code&gt;-Wl,-soname,$(DYLIB_MINOR_NAME)&lt;/code&gt;，该项生成一个链接文件，但我没找到xlc对应的选项，只好直接删掉，在make项目中手动加上ln命令。&lt;/p&gt;
&lt;p&gt;修改.c.o项目的编译命令，将&lt;code&gt;-std=c99&lt;/code&gt;改为&lt;code&gt;-qlanglvl=stdc99&lt;/code&gt;，删掉&lt;code&gt;-pedantic&lt;/code&gt;（没找到对应选项）。&lt;/p&gt;
&lt;h3 id="lua"&gt;lua&lt;/h3&gt;
&lt;p&gt;lua库的Makefile和src/Makefile文件中有针对aix的编译选项，需将PLAT设置为aix。下面修改只针对src/Makefile文件。&lt;/p&gt;
&lt;p&gt;设置MYCFLAGS变量为&lt;code&gt;-qlanglvl=stdc99&lt;/code&gt;，在aix项目中的CFLAGS中加入&lt;code&gt;-qlanglvl=stdc99&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="源文件修改"&gt;源文件修改&lt;/h2&gt;
&lt;p&gt;同上，需要修改Makefile文件。&lt;/p&gt;
&lt;p&gt;将&lt;code&gt;-std=c99&lt;/code&gt;修改为&lt;code&gt;-qlanglvl=stdc99&lt;/code&gt;，删掉DEBUG中的&lt;code&gt;-ggdb&lt;/code&gt;。修改链接命令，将&lt;code&gt;FINAL_LDFLAGS&lt;/code&gt;从&lt;code&gt;-rdynamic&lt;/code&gt;修改为&lt;code&gt;-bdynamic&lt;/code&gt;，将&lt;code&gt;FINAL_LIBS&lt;/code&gt;修改为&lt;code&gt;-lpthread&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;redis的Makefile中只有简单的install命令，但我没有系统权限，所以只好将所有的install命令都改成cp。&lt;/p&gt;
&lt;h2 id="编译"&gt;编译&lt;/h2&gt;
&lt;p&gt;使用gmake编译，gmake install安装，可以正常使用。不过系统中没有tcl，无法完成测试。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;p&gt;《&lt;a href="//www.blogways.net/blog/2013/06/21/aix-redis.html"&gt;AIX下编译redis代码&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="附注"&gt;附注&lt;/h2&gt;
&lt;p&gt;尝试在AIX下编译软件是个既无趣又浪费时间的事情，以后还是少费时间在这上面，多做些有意义的事情。&lt;/p&gt;</description></item><item><title>GRAPES MESO模式学习笔记08-4 —— 提取公共变量到配置文件</title><link>https://blog.perillaroc.wang/post/2014/2014-08-20-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb008-4-e68f90e58f96e585ace585b1e58f98e9878fe588b0e9858de7bdaee69687e4bbb6/</link><pubDate>Wed, 20 Aug 2014 18:08:33 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-20-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb008-4-e68f90e58f96e585ace585b1e58f98e9878fe588b0e9858de7bdaee69687e4bbb6/</guid><description/></item><item><title>GRAPES MESO模式学习笔记08-3 —— 使用Python改写脚本</title><link>https://blog.perillaroc.wang/post/2014/2014-08-20-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb008-3-e4bdbfe794a8pythone694b9e58699e8849ae69cac/</link><pubDate>Wed, 20 Aug 2014 17:46:09 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-20-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb008-3-e4bdbfe794a8pythone694b9e58699e8849ae69cac/</guid><description/></item><item><title>GrADS格点数据文件解析</title><link>https://blog.perillaroc.wang/post/2014/2014-08-18-grad-gridded-data-file-parse/</link><pubDate>Mon, 18 Aug 2014 16:50:22 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-18-grad-gridded-data-file-parse/</guid><description>&lt;p&gt;本文介绍 GrADS 格点数据的描述文件的解析和二进制数据文件的读取。&lt;/p&gt;
&lt;p&gt;关于 GrADS 格点数据格式的详细介绍，请浏览《&lt;a href="https://blog.perillaroc.wang/post/2014/2014-08-18-grads-gridded-data-file-structure/"&gt;GrADS格点数据格式&lt;/a&gt;》。&lt;/p&gt;
&lt;h2 id="数据描述文件解析"&gt;数据描述文件解析&lt;/h2&gt;
&lt;p&gt;从数据描述文件 (简称 ctl 文件) 格式来看，每个独立的 ctl 语句行都以一个关键字开头。
有些关键字只有一行语句，比如 &lt;code&gt;dset&lt;/code&gt;、&lt;code&gt;title&lt;/code&gt; 等；有些关键字可能有多行语句，比如 &lt;code&gt;zdef&lt;/code&gt;、&lt;code&gt;vars&lt;/code&gt; 等，后续语句行数都可以从第一行语句中得到。&lt;/p&gt;
&lt;p&gt;所以解析 ctl 文件是顺序读取每行，第一个单词为关键字，根据关键字采取相应的操作，比如 &lt;code&gt;dset&lt;/code&gt; 只需读当前行，而 &lt;code&gt;vars&lt;/code&gt; 需要读取后面所有的变量记录加上 &lt;code&gt;endvars&lt;/code&gt; 关键字，返回最后读取的行数。
接下来继续从下一行开始解析文件。&lt;/p&gt;
&lt;p&gt;框架图后续补充。&lt;/p&gt;
&lt;p&gt;首先将 ctl 文件内容保存为字符串数组&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctl_file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Path(ctl_file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; open(ctl_file_path) &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;readlines()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctl_file_lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [l&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip() &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; l &lt;span style="color:#f92672"&gt;in&lt;/span&gt; lines]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cur_no &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按顺序解析，读取一行，得到该行对应的解析器，运行解析器，解析器可能会读取更多的行，再从新一行继续解析&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; len(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctl_file_lines)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cur_no &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; total_lines:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cur_line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ctl_file_lines[self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cur_no]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; first_word &lt;span style="color:#f92672"&gt;=&lt;/span&gt; cur_line[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;:cur_line&lt;span style="color:#f92672"&gt;.&lt;/span&gt;find(&lt;span style="color:#e6db74"&gt;&amp;#39; &amp;#39;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; first_word&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lower() &lt;span style="color:#f92672"&gt;in&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;parser_mapper:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;parser_mapper[first_word]()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;cur_no &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个关键字对应一个解析器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;parser_mapper &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ctl_file_name&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_ctl_file_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;dset&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_dset,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;options&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_options,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_title,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;undef&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_undef,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;xdef&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_dimension,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ydef&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_dimension,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;zdef&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_dimension,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;tdef&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_tdef,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;vars&amp;#39;&lt;/span&gt;: self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;_parse_vars,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面介绍一些解析器&lt;/p&gt;</description></item><item><title>GrADS格点数据格式</title><link>https://blog.perillaroc.wang/post/2014/2014-08-18-grads-gridded-data-file-structure/</link><pubDate>Mon, 18 Aug 2014 16:02:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-18-grads-gridded-data-file-structure/</guid><description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;模式运行输出结果为 GrADS 格点数据格式，包括二进制数据文件和描述文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;描述文件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;data descriptor file, 或者 control file，通常以扩展名 &lt;code&gt;.ctl&lt;/code&gt; 结尾，包含对二进制数据的文件位置，及数据信息完整描述，包括网格、时间、经纬度信息、层次、变量等信息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二进制数据文件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;binary data file，通常以扩展名 &lt;code&gt;.dat&lt;/code&gt; 结尾或者没有扩展名。
只保存数据值，没有时间等信息。&lt;/p&gt;
&lt;p&gt;为了快速掌握 GrADS 格点数据格式，从实例文件开始学习，研究每条语句的含义。&lt;/p&gt;
&lt;h2 id="数据描述文件ctl文件"&gt;数据描述文件(ctl文件)&lt;/h2&gt;
&lt;p&gt;下面是某个 ctl 文件的样例，来自 GRAPES MESO v4.0 的模式积分输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;12
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;13
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;14
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;15
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;16
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;17
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;18
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;19
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;20
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;21
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;22
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;23
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;24
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;25
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;26
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;27
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;28
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;29
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;30
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;31
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;32
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;33
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;34
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;35
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;36
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;37
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;38
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;39
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;40
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;41
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;42
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;43
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;44
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;45
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;46
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;47
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;48
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;49
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;50
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;51
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;52
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;53
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;54
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;55
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;56
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;57
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;58
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;59
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;60
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;61
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;62
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;63
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;64
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;65
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;66
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dset ^postvar201408110000100
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;options sequential big_endian
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;title post output from grapes
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;undef 9.999E+20
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;xdef 751 linear 70.0000 0.1000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ydef 501 linear 15.0000 0.1000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zdef 26 levels
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	1000.000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	975.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	950.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	925.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	900.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	850.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	800.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	750.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	700.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	650.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	600.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	550.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	500.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	450.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	400.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	350.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	300.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	250.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	200.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	150.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	100.0000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	70.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	50.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	30.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	20.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	10.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tdef 1 linear 01z11AUG2014 60mn
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vars 30
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	u 26 0 u_wind
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	v 26 0 v_wind
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	t 26 0 temperature
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	h 26 0 geopotential height
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Qv 26 0 Q vapor
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Qc 26 0 Q cloud
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Qr 26 0 Q rain
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Qi 26 0 Q ice
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Qs 26 0 Q snow
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	Qg 26 0 Q grapaul
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	w 26 0 vertical wind
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ps 0 0 surface pressure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	psl 0 0 sea level pressure
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	rainc 0 0 precipitation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	rainnc 0 0 precipitation
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	ts 0 0 surface temperature
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	glw 0 0 surface long wave radiation flux
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	gsw 0 0 surface short wave radiation flux
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	hfx 0 0 surface heat flux
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	qfx 0 0 surface vapour flux
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	q2m 0 0 vapour at 2m
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	t2m 0 0 t at 2m
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	u10m 0 0 u at 10m
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	v10m 0 0 v at 10m
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	lu 0 0 land use
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	zs 0 0 terrain
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	tmn 0 0 tmn
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	cr 0 0 cr in dbz
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	tslb 4 0 tslb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	mslb 4 0 mslb
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;endvars
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="数据文件名"&gt;数据文件名&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;1&lt;/span&gt;&lt;span&gt;dset ^postvar201408110000100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;dest&lt;/code&gt; 表示描述文件对应的数据文件名，&lt;code&gt;^&lt;/code&gt; 表示当前数据描述文件所在的目录。&lt;/p&gt;</description></item><item><title>字节顺序--大端存储和小端存储</title><link>https://blog.perillaroc.wang/post/2014/2014-08-06-bite-order-big-or-little/</link><pubDate>Wed, 06 Aug 2014 17:11:38 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-06-bite-order-big-or-little/</guid><description>&lt;blockquote&gt;
&lt;p&gt;从哪一端（大端还是小端）打开半熟的鸡蛋？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;对于多字节的数据，必须搞清楚两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;地址是什么&lt;/li&gt;
&lt;li&gt;在存储器中如何排列字节&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第一个问题，存储器大都一样，将多字节数据存放在连续的地址中，将所用字节中最小的地址作为数据的地址。但第二个问题却分成两派：大端派 (big endian) 和小端派 (little endian)。&lt;/p&gt;
&lt;p&gt;大小端指的数据在连续地址中的排序方式，大端将从数据最高有效字节开始存放，小端从数据最低有效字节开始存放。
打个比方，存放数据 &lt;code&gt;0x1234&lt;/code&gt; 需要四个字节，大端将最高字节 &lt;code&gt;1&lt;/code&gt; 放在最小地址，小端将最低字节 &lt;code&gt;4&lt;/code&gt; 放在最小地址。&lt;/p&gt;
&lt;p&gt;举一个详细的例子说明上述问题。
在 32 位机器中存放 int 型整数 &lt;code&gt;19088743&lt;/code&gt; (=&lt;code&gt;0x01234567&lt;/code&gt;)，需要四个字节，起始地址在 &lt;code&gt;0x10&lt;/code&gt;，地址范围为 &lt;code&gt;0x10-0x13&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;大端法：&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ww4.sinaimg.cn/mw690/4afdac38jw1ej30da30s6j20co01zdfs.jpg" alt="大端存储"&gt;&lt;/p&gt;
&lt;p&gt;小端法&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ww4.sinaimg.cn/mw690/4afdac38jw1ej30daepb0j20co01zaa0.jpg" alt="小端存储"&gt;&lt;/p&gt;
&lt;h2 id="大小端检测"&gt;大小端检测&lt;/h2&gt;
&lt;p&gt;C 检测大小端的程序&lt;/p&gt;
&lt;p&gt;来自 stackoverflow 的问题回复 《&lt;a href="//stackoverflow.com/questions/1001307/detecting-endianness-programmatically-in-a-c-program"&gt;Detecting endianness programmatically in a C++ program&lt;/a&gt;》&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_big_endian&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;union&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uint32_t&lt;/span&gt; i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; c[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } bint &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#ae81ff"&gt;0x01020304&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; bint.c[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;回答人说使用 &lt;code&gt;union&lt;/code&gt; 比使用指针转换好，不会有警告。&lt;/p&gt;
&lt;h2 id="测试程序"&gt;测试程序&lt;/h2&gt;
&lt;h3 id="测试程序1"&gt;测试程序1&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; std;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_big_endian&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;union&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;uint32_t&lt;/span&gt; i;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; c[&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } bint &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#ae81ff"&gt;0x01020304&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; bint.c[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cout&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;is_big_endian()&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;endl;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试结果&lt;/p&gt;</description></item><item><title>GRAPES MESO模式学习笔记08-2 —— SMS中使用Python脚本</title><link>https://blog.perillaroc.wang/post/2014/2014-08-04-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb008-2-smse4b8ade4bdbfe794a8pythone8849ae69cac/</link><pubDate>Mon, 04 Aug 2014 09:32:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-04-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb008-2-smse4b8ade4bdbfe794a8pythone8849ae69cac/</guid><description/></item><item><title>GRAPES MESO模式学习笔记08-1 —— 使用LoadLeveler运行python脚本</title><link>https://blog.perillaroc.wang/post/2014/2014-08-01-grapes-meso-notebook-run-python-on-loadleveler/</link><pubDate>Fri, 01 Aug 2014 15:35:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-08-01-grapes-meso-notebook-run-python-on-loadleveler/</guid><description>&lt;p&gt;目前业务中的LoadLeveler作业脚本都是shell脚本，在头部加入LoadLeveler的脚本命令（以#开头，类似shell的注释）。&lt;/p&gt;
&lt;p&gt;LoadLeveler中作业文件(job file)与可执行程序(program to run)是两个不同的概念，作业脚本执行&lt;code&gt;executable&lt;/code&gt;变量指定的程序。没有设置&lt;code&gt;executable&lt;/code&gt;变量时，执行程序就是作业脚本本身。这样的脚本既能直接运行，也可以用LoadLeveler提交运行，便于测试。&lt;/p&gt;
&lt;p&gt;shell脚本、python脚本、perl脚本都可以在UNIX系统直接运行，所以LoadLeveler也支持Python脚本。&lt;/p&gt;
&lt;h2 id="基本用法"&gt;基本用法&lt;/h2&gt;
&lt;p&gt;python脚本以&lt;code&gt;#!/bin/env python&lt;/code&gt;开头。一个简单的作业脚本如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/env python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ job_type=serial&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ input=/dev/null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ output = ./myjob.out.$(stepid)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ error = ./myjob.out.err.$(stepid)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ notification = never&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ checkpoint = no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ restart = no&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ class= normal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ comment = WRF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ node_usage = shared&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @ queue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; subprocess
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print &lt;span style="color:#e6db74"&gt;&amp;#34;Begin to start 10 tasks...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print &lt;span style="color:#e6db74"&gt;&amp;#34;Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt; hello&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;call(&lt;span style="color:#e6db74"&gt;&amp;#34;sleep 1;echo &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{i}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;i),shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print &lt;span style="color:#e6db74"&gt;&amp;#34;Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%d&lt;/span&gt;&lt;span style="color:#e6db74"&gt; done&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print &lt;span style="color:#e6db74"&gt;&amp;#34;Task Done&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出文件myjob.out.0内容为：&lt;/p&gt;</description></item><item><title>[2014.07.30] 切换的代价</title><link>https://blog.perillaroc.wang/post/2014/2014-07-30-2014-07-30-e58887e68da2e79a84e4bba3e4bbb7/</link><pubDate>Wed, 30 Jul 2014 17:17:19 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-30-2014-07-30-e58887e68da2e79a84e4bba3e4bbb7/</guid><description>&lt;p style="text-align: right;"&gt;</description></item><item><title>使用Crayon Syntax Highlighter插件代替SyntaxHighlighter Evolved插件</title><link>https://blog.perillaroc.wang/post/2014/2014-07-26-e4bdbfe794a8crayon-syntax-highlightere68f92e4bbb6e4bba3e69bbfsyntaxhighlighter-evolvede68f92e4bbb6/</link><pubDate>Sat, 26 Jul 2014 22:31:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-26-e4bdbfe794a8crayon-syntax-highlightere68f92e4bbb6e4bba3e69bbfsyntaxhighlighter-evolvede68f92e4bbb6/</guid><description/></item><item><title>替换WordPress中引用googleapis的库</title><link>https://blog.perillaroc.wang/post/2014/2014-07-25-e69bbfe68da2wordpresse4b8ade5bc95e794a8googleapise79a84e5ba93/</link><pubDate>Fri, 25 Jul 2014 08:46:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-25-e69bbfe68da2wordpresse4b8ade5bc95e794a8googleapise79a84e5ba93/</guid><description/></item><item><title>[GRIB API]在AIX下编译GRIB API</title><link>https://blog.perillaroc.wang/post/2014/2014-07-18-grib-api-notebook-build-on-aix/</link><pubDate>Fri, 18 Jul 2014 10:21:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-18-grib-api-notebook-build-on-aix/</guid><description>&lt;p&gt;AIX编译GRIB API V1.12.3&lt;/p&gt;
&lt;h2 id="概述"&gt;概述&lt;/h2&gt;
&lt;p&gt;configure命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;XXX --with-jasper&lt;span style="color:#f92672"&gt;=&lt;/span&gt;XXX &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --enable-pthread &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlc FC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlf &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; CFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-g -qcpluscmt -qlanglvl=extended -qansialias&amp;#39;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FCFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-g -qextname -qlanglvl=extended&amp;#39;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-g -qextname&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后make时会出现错误&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;libtool: link: xlc -pedantic -Wall -DYYDEBUG -g -qcpluscmt -qlanglvl=extended -qansialias ...
xlc: 1501-289 (W) Option -Wall was incorrectly specified. The option will be ignored.
ld: 0711-327 WARNING: Entry point not found: dantic
ld: 0711-244 ERROR: No csects or exported symbols have been saved.
make: The error code from the last command is 8.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;主要因为xlc编译时添加&lt;code&gt;-pedantic&lt;/code&gt;选项，去掉该选项就可以编译通过。&lt;/p&gt;</description></item><item><title>GRAPES MESO模式学习笔记07——脚本运行之产品生成</title><link>https://blog.perillaroc.wang/post/2014/2014-07-08-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb007-e8849ae69cace8bf90e8a18ce4b98be4baa7e59381e7949fe68890/</link><pubDate>Tue, 08 Jul 2014 22:56:11 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-08-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb007-e8849ae69cace8bf90e8a18ce4b98be4baa7e59381e7949fe68890/</guid><description/></item><item><title>QStandardItemModel中设置项目的背景颜色</title><link>https://blog.perillaroc.wang/post/2014/2014-07-04-qstandarditemmodele4b8ade8aebee7bdaee9a1b9e79baee79a84e8838ce699afe9a29ce889b2/</link><pubDate>Fri, 04 Jul 2014 11:05:48 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-04-qstandarditemmodele4b8ade8aebee7bdaee9a1b9e79baee79a84e8838ce699afe9a29ce889b2/</guid><description/></item><item><title>GRAPES MESO模式学习笔记06——脚本运行之后处理</title><link>https://blog.perillaroc.wang/post/2014/2014-07-03-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb005-e8849ae69cace8bf90e8a18ce4b98be5908ee5a484e79086/</link><pubDate>Thu, 03 Jul 2014 14:25:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-07-03-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb005-e8849ae69cace8bf90e8a18ce4b98be5908ee5a484e79086/</guid><description/></item><item><title>GRAPES MESO模式学习笔记05——脚本运行之模式预报</title><link>https://blog.perillaroc.wang/post/2014/2014-06-19-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb005-e8849ae69cace8bf90e8a18ce4b98be6a8a1e5bc8fe9a284e68aa5/</link><pubDate>Thu, 19 Jun 2014 09:27:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-06-19-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb005-e8849ae69cace8bf90e8a18ce4b98be6a8a1e5bc8fe9a284e68aa5/</guid><description/></item><item><title>GRAPES MESO模式学习笔记04——脚本运行之资料同化</title><link>https://blog.perillaroc.wang/post/2014/2014-06-06-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb004-e8849ae69cace8bf90e8a18ce4b98be8b584e69699e5908ce58c96/</link><pubDate>Fri, 06 Jun 2014 15:02:29 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-06-06-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb004-e8849ae69cace8bf90e8a18ce4b98be8b584e69699e5908ce58c96/</guid><description/></item><item><title>GRAPES MESO模式学习笔记03——脚本运行之标准初始化</title><link>https://blog.perillaroc.wang/post/2014/2014-06-06-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb003-e8849ae69cace8bf90e8a18ce4b98be6a087e58786e5889de5a78be58c96/</link><pubDate>Fri, 06 Jun 2014 14:08:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-06-06-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb003-e8849ae69cace8bf90e8a18ce4b98be6a087e58786e5889de5a78be58c96/</guid><description/></item><item><title>GRAPES MESO模式学习笔记02——脚本运行之资料预处理</title><link>https://blog.perillaroc.wang/post/2014/2014-05-29-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb002-e8849ae69cace8bf90e8a18ce4b98be8b584e69699e9a284e5a484e79086/</link><pubDate>Thu, 29 May 2014 16:53:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-05-29-grapes-mesoe6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb002-e8849ae69cace8bf90e8a18ce4b98be8b584e69699e9a284e5a484e79086/</guid><description/></item><item><title>GRAPES MESO模式学习笔记01——脚本运行</title><link>https://blog.perillaroc.wang/post/2014/2014-05-27-grapes-meso-notebook-script-run/</link><pubDate>Tue, 27 May 2014 23:00:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-05-27-grapes-meso-notebook-script-run/</guid><description>&lt;p&gt;因为我不懂模式原理，所以只能关心模式运行，也就是跑一遍模式而已。下面简单记录下我尝试跑GRAPES MESO V3.3.2.4的过程。&lt;/p&gt;
&lt;h1 id="概述"&gt;概述&lt;/h1&gt;
&lt;p&gt;借用文档中的一幅图来说明GRAPES MESO的结构。&lt;/p&gt;
&lt;figure style="width: 690px" class="wp-caption alignnone"&gt;&lt;img alt="" src="http://ww4.sinaimg.cn/mw690/4afdac38gw1egt7d8psngj20nj0i6422.jpg" width="690" height="532" /&gt;&lt;figcaption class="wp-caption-text"&gt;GRAPES MESO系统结构图&lt;/figcaption&gt;&lt;/figure&gt; 
系统由四个基本部分组成：
&lt;ul&gt;
&lt;li&gt;&lt;span style="line-height: 13px;"&gt;预处理&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;标准初始化&lt;/li&gt;
&lt;li&gt;同化预报&lt;/li&gt;
&lt;li&gt;后处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个模块的具体功能我还不是很清楚，先跑起来看看。&lt;/p&gt;
&lt;h1 id="获取代码"&gt;获取代码&lt;/h1&gt;
&lt;p&gt;可以从气象信息中心的Perforce版本库中获取最新的GRAPES版本，截止本文发布时，最新的发布版本为V3.3.2.4，GRAPES MESO的4.0版本正在集成测试，正式发布前我先看稳定版本。&lt;br&gt;
跑模式测试还需要静态资料和测试数据，这两者可以从气象中心的FTP上下载，或在HPC的实验户头的/cma/g3/nwp_ex/share目录下寻找，当然也可以在共享目录中找到需要的一切数据。&lt;/p&gt;
&lt;h1 id="安装"&gt;安装&lt;/h1&gt;
&lt;p&gt;获取代码后，先看下代码的目录结构&lt;/p&gt;
&lt;h2 id="代码目录结构"&gt;代码目录结构&lt;/h2&gt;
&lt;p&gt;4dvar         变分同化&lt;br&gt;
data_proc     处理背景场数据&lt;br&gt;
doc&lt;br&gt;
fcst          模式积分（前后处理、动力框架、物理过程）&lt;br&gt;
gcas&lt;br&gt;
operation     业务运行SMS脚本&lt;br&gt;
sh            模式运行脚本&lt;br&gt;
verify        检验&lt;br&gt;
以及版本的ChangeList和ReleaseNotes。&lt;/p&gt;
&lt;h2 id="数据"&gt;数据&lt;/h2&gt;
&lt;p&gt;背景场：支持NCEP_EPS和T639，我先使用T639作为模式背景场。&lt;br&gt;
变分同化：探空+其它&lt;br&gt;
静态资料：与WRF相同&lt;/p&gt;
&lt;h2 id="配置文件"&gt;配置文件&lt;/h2&gt;
&lt;p&gt;需要/fcst/grapes_model/configure.si中修改netcdf库的位置&lt;br&gt;
HPC上安装的NetCDF库在/cma/u/app/netcdf&lt;/p&gt;
&lt;h1 id="编译"&gt;编译&lt;/h1&gt;
&lt;p&gt;提供整体编译脚本：sh/compile.sh [AIX|INTEL]。&lt;br&gt;
也可以手动编译各个模块。手动编译以后研究每个模块的时候再试。&lt;br&gt;
编译结束时一定要检查编译输出，查看是否有错误。第一次编译时我没修改NetCDF路径，编译过程似乎也是正常结束了，其实编译错误就隐藏在输出中，所以必须要查看输出。&lt;/p&gt;
&lt;h1 id="脚本运行"&gt;脚本运行&lt;/h1&gt;
&lt;p&gt;首先感受一下模式，先用代码提供的测试脚本跑一遍。不过运行脚本前需要修改一些参数。&lt;/p&gt;
&lt;h2 id="修改shteshsh"&gt;修改sh/tesh.sh&lt;/h2&gt;
&lt;p&gt;设置运行平台、起报时间、积分时长、是否做静态资料和变分同化。根据数据设置相应时间。&lt;/p&gt;
&lt;h2 id="修改everyday_t639datash"&gt;修改everyday_t639data.sh&lt;/h2&gt;
&lt;p&gt;使用nwp_ex目录下面的背景场，为2013年4月10日&lt;br&gt;
设置目录&lt;br&gt;
GEODATA_DIR：静态资料&lt;br&gt;
/cma/g2/COMMDATA/static/rfs/geog/v3&lt;br&gt;
OBS_DIR：观测资料&lt;br&gt;
/cma/g2/COMMDATA/obs/aob/2013&lt;br&gt;
bckgdata_dir：背景场资料&lt;br&gt;
/cma/g2/COMMDATA/OPER/nwp/GMFS_GRIB2_T639/T639GSI2GRIB2_ORIG_$1&lt;br&gt;
/cma/g3/nwp_ex/share/test/rfs/data/T639_data&lt;br&gt;
测试脚本使用起报时刻12小时之前的预报作为背景场，所以不能用$1（起报时间），应该减去12小时。为了简便，不修改脚本，直接使用实验组提供的数据集。&lt;br&gt;
设置参数&lt;br&gt;
修改队列参数/fcst/grapes_model/run/grapes.cmd&lt;br&gt;
将原来的class为smalljob修改为normal&lt;/p&gt;
&lt;h2 id="运行test_t639datash"&gt;运行test_t639data.sh&lt;/h2&gt;
&lt;p&gt;后台运行脚本&lt;br&gt;
[shell]&lt;br&gt;
nohup test_t639data.sh &amp;gt; t639data.out 2&amp;gt;&amp;amp;1 &amp;amp;&lt;br&gt;
[/shell]&lt;br&gt;
日志：运行日志被分解成多个文件，分布在不同目录&lt;br&gt;
最顶层：t639data.out 脚本调用，无用&lt;br&gt;
/sh/grapes_log/grapes.log.2013041012：everyday脚本的日志&lt;br&gt;
/fcst/grapes_model/run /printout/si.log.2013041012：si模块的日志&lt;br&gt;
/fcst/grapes_model/run /printout/grapes_555090.err grapes_555090.out：grapes.exe的loadleveler作业日志&lt;/p&gt;</description></item><item><title>AIX编译Autotools</title><link>https://blog.perillaroc.wang/post/2014/2014-05-01-build-autotools-on-aix/</link><pubDate>Thu, 01 May 2014 14:44:09 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-05-01-build-autotools-on-aix/</guid><description>&lt;p&gt;单位AIX上的autoconf和automake无法使用，必须得自己编译。&lt;/p&gt;
&lt;h2 id="软件清单"&gt;软件清单&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;m4&lt;/li&gt;
&lt;li&gt;emacs*&lt;/li&gt;
&lt;li&gt;autoconf&lt;/li&gt;
&lt;li&gt;automake&lt;/li&gt;
&lt;li&gt;libtool&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;编译autoconf竟然需要emacs，单位AIX的emacs也无法使用，需要自己安装。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="编译"&gt;编译&lt;/h2&gt;
&lt;h3 id="m4"&gt;m4&lt;/h3&gt;
&lt;p&gt;需要指定xlC为C编译器&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/install CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC CFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;-q64 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="emacs"&gt;Emacs&lt;/h3&gt;
&lt;p&gt;编译Emacs一直没成功，无奈找了个aix的&lt;a href="//ftp.xemacs.org/pub/xemacs/binaries/aix/"&gt;二进制包&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="autoconf"&gt;autoconf&lt;/h3&gt;
&lt;p&gt;需要指定C编译器和EMACS目录。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/install &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EMACS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/emacs/bin &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EMACSLOADPATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/emcas/lib 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="automake"&gt;automake&lt;/h3&gt;
&lt;p&gt;指定C和Fortran编译器&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/install &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlf 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="libtool"&gt;libtool&lt;/h3&gt;
&lt;p&gt;指定C、C++、Fortran编译器。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./configure --prefix&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/path/to/install &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlC 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;F77&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlf &lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;xlf 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="使用"&gt;使用&lt;/h2&gt;
&lt;p&gt;发现aix下autoconf检测gcc出错会直接退出，所以使用&lt;code&gt;AC_PROG_CC&lt;/code&gt;之类的宏时，要先检测xlc，后检测gcc。&lt;/p&gt;</description></item><item><title>使用wgrib2插值GRIB2数据</title><link>https://blog.perillaroc.wang/post/2014/2014-04-28-interpolate-grib2-using-wgrib2/</link><pubDate>Mon, 28 Apr 2014 15:32:22 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-04-28-interpolate-grib2-using-wgrib2/</guid><description>&lt;p&gt;重采样grib2数据&lt;/p&gt;
&lt;p&gt;使用 wgrib2 可以将现有 grib2 数据转码成参数不同的 grib2 数据，例如修改投影方式、修改经纬度范围、插值等。
wgrib2 使用 &lt;code&gt;-new_grid&lt;/code&gt; 参数提供上述功能。&lt;/p&gt;
&lt;p&gt;详情参见：http://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/new_grid.html&lt;/p&gt;
&lt;h2 id="安装"&gt;安装&lt;/h2&gt;
&lt;p&gt;必须开启 makefile 中的 &lt;code&gt;USE_IPOLATES&lt;/code&gt; 编译 wgrib2 才可以使用插值功能。我在 cygwin 下编译通过。&lt;/p&gt;
&lt;h2 id="使用"&gt;使用&lt;/h2&gt;
&lt;p&gt;摘抄自官网&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-new_grid_winds W -new_grid A B C outfile
W = earth or grid
earth means that the U wind goes eastward
grid means that U wind goes from grid (i,j) to (i+1,j)
which is not eastward in a Lambert-conformal or polar stereographic grids
A, B, C are the output grid description
outfile is an output file. The grib-2 interpolated records are written in outfile
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;将经纬度分辨率改为 1 度，经度从 0 到 359，纬度从 -90 到 +89&lt;/p&gt;</description></item><item><title>GRIB API源码分析——grib_get_[TYPE]实现简析</title><link>https://blog.perillaroc.wang/post/2014/2014-04-24-grib-apie6ba90e7a081e58886e69e90-grib_get_typee5ae9ee78eb0e7ae80e69e90/</link><pubDate>Thu, 24 Apr 2014 12:59:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-04-24-grib-apie6ba90e7a081e58886e69e90-grib_get_typee5ae9ee78eb0e7ae80e69e90/</guid><description/></item><item><title>GRIB API源码分析——grib_count实现简析</title><link>https://blog.perillaroc.wang/post/2014/2014-04-21-grib-apie6ba90e7a081e58886e69e90-grib_counte5ae9ee78eb0e7ae80e69e90/</link><pubDate>Mon, 21 Apr 2014 22:58:49 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-04-21-grib-apie6ba90e7a081e58886e69e90-grib_counte5ae9ee78eb0e7ae80e69e90/</guid><description/></item><item><title>批量下载Coursera资源</title><link>https://blog.perillaroc.wang/post/2014/2014-04-12-e689b9e9878fe4b88be8bdbdcourserae8b584e6ba90/</link><pubDate>Sat, 12 Apr 2014 14:52:54 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-04-12-e689b9e9878fe4b88be8bdbdcourserae8b584e6ba90/</guid><description/></item><item><title>Windwos下打包PyQt5应用程序</title><link>https://blog.perillaroc.wang/post/2014/2014-03-25-windwose4b88be68993e58c85pyqt5e5ba94e794a8e7a88be5ba8f/</link><pubDate>Tue, 25 Mar 2014 13:07:12 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-25-windwose4b88be68993e58c85pyqt5e5ba94e794a8e7a88be5ba8f/</guid><description/></item><item><title>Windows下在Python 2.7的virtualenv中编译PyQt5</title><link>https://blog.perillaroc.wang/post/2014/2014-03-24-build-pyqt5-using-python-27-virtualenv-on-windows/</link><pubDate>Mon, 24 Mar 2014 22:47:38 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-24-build-pyqt5-using-python-27-virtualenv-on-windows/</guid><description>&lt;blockquote&gt;
&lt;p&gt;该文章中的方法已过时，请使用&lt;code&gt;pip install pyqt5&lt;/code&gt;直接安装PyQt&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PyQt5只提供Python3的二进制包，而且PyQt的安装包不支持virtualenv，所以我选择手动编译PyQt5。&lt;/p&gt;
&lt;h2 id="环境"&gt;环境&lt;/h2&gt;
&lt;p&gt;Python2.7，32位版本。&lt;/p&gt;
&lt;p&gt;Qt 5.2.1 版本，我使用官方vs2010的预编译包。&lt;/p&gt;
&lt;p&gt;编译器，鉴于我使用vs2010版的Qt，我使用VS2008作为编译器。Python的二进制包似乎由vs2008变异而来。&lt;/p&gt;
&lt;h2 id="python源码包"&gt;Python源码包&lt;/h2&gt;
&lt;p&gt;SIP：sip-4.15.5.zip&lt;/p&gt;
&lt;p&gt;PyQt5：PyQt-gpl-5.2.1.zip&lt;/p&gt;
&lt;p&gt;两者均从PyQt的官网上下载。&lt;/p&gt;
&lt;h2 id="准备"&gt;准备&lt;/h2&gt;
&lt;p&gt;创建全新的virtualenv环境：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;virtualenv --no-site-packages ENV 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进入编译环境&lt;/p&gt;
&lt;p&gt;编译PyQt需要qt工具和编译器，所以我先进入VS2008的命令行，再将QT的bin目录加入到PATH变量中。然后再启动虚拟环境。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ENV/Scripts/activate 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为编译sip时需要python27.lib，但如此建立虚拟环境时没有拷贝python\libs目录，所以将python的libs目录拷贝到ENV目录下。&lt;/p&gt;
&lt;p&gt;编译时还需要python\include目录，所以也将include拷贝到ENV目录下。&lt;/p&gt;
&lt;h2 id="编译"&gt;编译&lt;/h2&gt;
&lt;p&gt;参照官方安装说明即可。&lt;/p&gt;
&lt;h3 id="编译sip"&gt;编译sip&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python configure.py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nmake
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nmake install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装后，sip.exe被拷贝到ENV目录下，但在虚拟环境的PATH中只有ENV\Scripts目录，在下一步编译PyQt是会使用sip.exe，所以要将sip.exe拷贝到Scripts目录下。&lt;/p&gt;
&lt;h3 id="编译pyqt5"&gt;编译PyQt5&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python configure.py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nmake
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nmake install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="使用pyqt5"&gt;使用PyQt5&lt;/h3&gt;
&lt;p&gt;使用PyQt5时，需要保证PATH中含有qt5的动态链接库文件，无法找到qt5的dll文件，导入模块时就会出错。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ImportError: DLL load failed: 找不到指定的模块。
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如此即可使用PyQt5.&lt;/p&gt;</description></item><item><title>Windows下使用GRIB API库</title><link>https://blog.perillaroc.wang/post/2014/2014-03-24-windowse4b88be4bdbfe794a8grib-apie5ba93/</link><pubDate>Mon, 24 Mar 2014 09:15:46 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-24-windowse4b88be4bdbfe794a8grib-apie5ba93/</guid><description/></item><item><title>QVariant保存指针数据</title><link>https://blog.perillaroc.wang/post/2014/2014-03-17-save-pointer-in-qvariant/</link><pubDate>Mon, 17 Mar 2014 13:16:43 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-17-save-pointer-in-qvariant/</guid><description>&lt;h2 id="方案"&gt;方案&lt;/h2&gt;
&lt;p&gt;QVariant 默认无法保存指针数据，因为以&lt;code&gt;void *&lt;/code&gt;为参数的 &lt;code&gt;QVariant&lt;/code&gt; 构造函数是私有的。&lt;/p&gt;
&lt;p&gt;但通过 QT 提供的 Meta Type 机制，可以将任意指针存放到 &lt;code&gt;QVariant&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;需要使用&lt;code&gt;Q_DECLARE_METATYPE&lt;/code&gt;宏注册类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Q_DECLARE_METATYPE(QStandardItemModel&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后，就可以使用&lt;code&gt;QVariant::fromValue&lt;/code&gt;存放数据，使用&lt;code&gt;QVariant::value&lt;/code&gt;获取数据了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QVariant&lt;span style="color:#f92672"&gt;::&lt;/span&gt;fromValue(model_);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QStandardItemModel&lt;span style="color:#f92672"&gt;*&lt;/span&gt; model &lt;span style="color:#f92672"&gt;=&lt;/span&gt; some_value.value();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="示例"&gt;示例&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;QVariant&lt;/code&gt; 和标识项目中数据类型的 &lt;code&gt;Qt::ItemDataRole&lt;/code&gt;，可以方便地将任意数据存放进 QT 提供的预定义模型中。&lt;/p&gt;
&lt;p&gt;比如，在同一个 &lt;code&gt;QStandardItem&lt;/code&gt; 中使用不同的 Role，存放多个数据。&lt;/p&gt;
&lt;p&gt;自定义的数据角色&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;CustomItemRole&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LevelModelRole &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Qt&lt;span style="color:#f92672"&gt;::&lt;/span&gt;UserRole &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TimeModelRole &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Qt&lt;span style="color:#f92672"&gt;::&lt;/span&gt;UserRole &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1010&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FileModelRole &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Qt&lt;span style="color:#f92672"&gt;::&lt;/span&gt;UserRole &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1020&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;存放特定角色的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;type_of_level_item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setData(QVariant&lt;span style="color:#f92672"&gt;::&lt;/span&gt;fromValue(level_list_model), LevelModelRole);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取特定角色的数据&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QVariant data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; item&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;data(Qt&lt;span style="color:#f92672"&gt;::&lt;/span&gt;LevelModelRole);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因为&lt;code&gt;QStandardItemModel&lt;/code&gt;以行为单位建立树形结构，所以要实现更复杂的树形结构，可以使用自定义的 DataRole 来存储数据。&lt;/p&gt;</description></item><item><title>使用QProgressDialog显示长时间任务的执行进度</title><link>https://blog.perillaroc.wang/post/2014/2014-03-13-e4bdbfe794a8qprogressdialoge698bee7a4bae995bfe697b6e997b4e4bbbbe58aa1e79a84e689a7e8a18ce8bf9be5baa6/</link><pubDate>Thu, 13 Mar 2014 13:24:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-13-e4bdbfe794a8qprogressdialoge698bee7a4bae995bfe697b6e997b4e4bbbbe58aa1e79a84e689a7e8a18ce8bf9be5baa6/</guid><description/></item><item><title>Notepad++远程编辑</title><link>https://blog.perillaroc.wang/post/2014/2014-03-07-notepade8bf9ce7a88be7bc96e8be91/</link><pubDate>Fri, 07 Mar 2014 13:54:52 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-07-notepade8bf9ce7a88be7bc96e8be91/</guid><description/></item><item><title>Windows升级MySQL</title><link>https://blog.perillaroc.wang/post/2014/2014-03-03-windowse58d87e7baa7mysql/</link><pubDate>Mon, 03 Mar 2014 11:07:28 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-03-windowse58d87e7baa7mysql/</guid><description/></item><item><title>sqlalchemy连接MySql数据库中文乱码</title><link>https://blog.perillaroc.wang/post/2014/2014-03-02-sqlalchemye8bf9ee68ea5mysqle695b0e68daee5ba93e4b8ade69687e4b9b1e7a081/</link><pubDate>Sun, 02 Mar 2014 10:19:15 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-03-02-sqlalchemye8bf9ee68ea5mysqle695b0e68daee5ba93e4b8ade69687e4b9b1e7a081/</guid><description/></item><item><title>Windows 7使用Vagrant构建虚拟开发环境</title><link>https://blog.perillaroc.wang/post/2014/2014-02-26-windows-7e4bdbfe794a8vagrante69e84e5bbbae8999ae68b9fe5bc80e58f91e78eafe5a283/</link><pubDate>Wed, 26 Feb 2014 23:33:11 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-02-26-windows-7e4bdbfe794a8vagrante69e84e5bbbae8999ae68b9fe5bc80e58f91e78eafe5a283/</guid><description/></item><item><title>在VMware试用Chrome OS</title><link>https://blog.perillaroc.wang/post/2014/2014-02-17-e59ca8vmwaree8af95e794a8chrome-os/</link><pubDate>Mon, 17 Feb 2014 20:48:35 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-02-17-e59ca8vmwaree8af95e794a8chrome-os/</guid><description/></item><item><title>使用Apache搭建Python服务器</title><link>https://blog.perillaroc.wang/post/2014/2014-01-27-e4bdbfe794a8apachee690ade5bbbapythone69c8de58aa1e599a8/</link><pubDate>Mon, 27 Jan 2014 16:11:15 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-27-e4bdbfe794a8apachee690ade5bbbapythone69c8de58aa1e599a8/</guid><description/></item><item><title>使用Autotools管理最简单的程序</title><link>https://blog.perillaroc.wang/post/2014/2014-01-23-e4bdbfe794a8autotoolse7aea1e79086e69c80e7ae80e58d95e79a84e7a88be5ba8f/</link><pubDate>Thu, 23 Jan 2014 09:51:23 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-23-e4bdbfe794a8autotoolse7aea1e79086e69c80e7ae80e58d95e79a84e7a88be5ba8f/</guid><description/></item><item><title>使用QSignalMapper处理信号</title><link>https://blog.perillaroc.wang/post/2014/2014-01-21-e4bdbfe794a8qsignalmappere5a484e79086e4bfa1e58fb7/</link><pubDate>Tue, 21 Jan 2014 22:36:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-21-e4bdbfe794a8qsignalmappere5a484e79086e4bfa1e58fb7/</guid><description/></item><item><title>动态修改QGridLayout</title><link>https://blog.perillaroc.wang/post/2014/2014-01-21-e58aa8e68081e4bfaee694b9qgridlayout/</link><pubDate>Tue, 21 Jan 2014 16:16:18 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-21-e58aa8e68081e4bfaee694b9qgridlayout/</guid><description/></item><item><title>升级Fedora 19到Fedora 20</title><link>https://blog.perillaroc.wang/post/2014/2014-01-20-e58d87e7baa7fedora-19e588b0fedora-20/</link><pubDate>Mon, 20 Jan 2014 23:22:33 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-20-e58d87e7baa7fedora-19e588b0fedora-20/</guid><description/></item><item><title>QMainwindow移植到QDialog</title><link>https://blog.perillaroc.wang/post/2014/2014-01-18-qmainwindow-to-qdialog/</link><pubDate>Sat, 18 Jan 2014 22:01:48 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-18-qmainwindow-to-qdialog/</guid><description/></item><item><title>GRIB API学习笔记（汇总）</title><link>https://blog.perillaroc.wang/post/2014/2014-01-01-grib-apie5ada6e4b9a0e7ac94e8aeb0efbc88e6b187e680bbefbc89/</link><pubDate>Wed, 01 Jan 2014 21:30:53 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-01-grib-apie5ada6e4b9a0e7ac94e8aeb0efbc88e6b187e680bbefbc89/</guid><description/></item><item><title>GRIB API学习笔记10——GRIB API高级话题2</title><link>https://blog.perillaroc.wang/post/2014/2014-01-01-grib-apie5ada6e4b9a0e7ac94e8aeb010-grib-apie9ab98e7baa7e8af9de9a2982/</link><pubDate>Wed, 01 Jan 2014 21:28:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-01-grib-apie5ada6e4b9a0e7ac94e8aeb010-grib-apie9ab98e7baa7e8af9de9a2982/</guid><description/></item><item><title>GRIB API学习笔记09——GRIB API高级话题1</title><link>https://blog.perillaroc.wang/post/2014/2014-01-01-grib-apie5ada6e4b9a0e7ac94e8aeb009-grib-apie9ab98e7baa7e8af9de9a2981/</link><pubDate>Wed, 01 Jan 2014 21:24:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2014/2014-01-01-grib-apie5ada6e4b9a0e7ac94e8aeb009-grib-apie9ab98e7baa7e8af9de9a2981/</guid><description/></item><item><title>GRIB API学习笔记08——GRIB API Python接口</title><link>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb008-grib-api-pythone68ea5e58fa3/</link><pubDate>Tue, 31 Dec 2013 21:39:26 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb008-grib-api-pythone68ea5e58fa3/</guid><description/></item><item><title>GRIB API学习笔记07——GRIB API库2</title><link>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb007-grib-apie5ba932/</link><pubDate>Tue, 31 Dec 2013 21:29:00 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb007-grib-apie5ba932/</guid><description/></item><item><title>GRIB API学习笔记06——grib_filter</title><link>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb006-grib_filter/</link><pubDate>Tue, 31 Dec 2013 21:18:53 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb006-grib_filter/</guid><description/></item><item><title>GRIB API学习笔记05——GRIB APIs 第一部分</title><link>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb005-grib-apis-e7acace4b880e983a8e58886/</link><pubDate>Tue, 31 Dec 2013 19:07:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-31-grib-apie5ada6e4b9a0e7ac94e8aeb005-grib-apis-e7acace4b880e983a8e58886/</guid><description/></item><item><title>GRIB API学习笔记04——GRIB命令行工具</title><link>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb004-gribe591bde4bba4e8a18ce5b7a5e585b7/</link><pubDate>Sat, 28 Dec 2013 17:38:20 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb004-gribe591bde4bba4e8a18ce5b7a5e585b7/</guid><description/></item><item><title>GRIB API学习笔记03——key</title><link>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb003-key/</link><pubDate>Sat, 28 Dec 2013 17:18:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb003-key/</guid><description/></item><item><title>GRIB API学习笔记02——GRIB介绍</title><link>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb002-gribe4bb8be7bb8d/</link><pubDate>Sat, 28 Dec 2013 17:12:20 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb002-gribe4bb8be7bb8d/</guid><description/></item><item><title>GRIB API学习笔记01——GRIB简介</title><link>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb001-gribe7ae80e4bb8b/</link><pubDate>Sat, 28 Dec 2013 11:50:09 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-28-grib-apie5ada6e4b9a0e7ac94e8aeb001-gribe7ae80e4bb8b/</guid><description/></item><item><title>Latex 图像排列显示</title><link>https://blog.perillaroc.wang/post/2013/2013-12-27-latex-e59bbee5838fe68e92e58897e698bee7a4ba/</link><pubDate>Fri, 27 Dec 2013 14:53:40 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-12-27-latex-e59bbee5838fe68e92e58897e698bee7a4ba/</guid><description/></item><item><title>Qt 5.1.1 应用程序打包</title><link>https://blog.perillaroc.wang/post/2013/2013-11-28-qt-5-1-1-e5ba94e794a8e7a88be5ba8fe68993e58c85/</link><pubDate>Thu, 28 Nov 2013 20:55:29 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-11-28-qt-5-1-1-e5ba94e794a8e7a88be5ba8fe68993e58c85/</guid><description/></item><item><title>IBM AIX下使用xlc编译boost库</title><link>https://blog.perillaroc.wang/post/2013/2013-11-08-build-boost-using-xlc-in-ibm-aix/</link><pubDate>Fri, 08 Nov 2013 09:29:33 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-11-08-build-boost-using-xlc-in-ibm-aix/</guid><description>&lt;p&gt;单位AIX 7.1下编译器xlc的版本为12.1，根据IBM网站&lt;a href="//www-01.ibm.com/support/docview.wss?uid=swg27027469"&gt;文章&lt;/a&gt;，推荐安装的boost版本为1.47.0。&lt;/p&gt;
&lt;p&gt;先从boost网站下载boost 1.47.0版本，解压缩到某目录。&lt;/p&gt;
&lt;p&gt;在从上述网址中下载IBM对boost 1.47.0版本的补丁文件boost_modfile.txt，在boost目录打补丁。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;patch -p0 &amp;lt; boost_modfile.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后使用运行&lt;code&gt;bootstrap.sh&lt;/code&gt;脚本，默认用gcc编译无法通过，需要制定编译套件。&lt;/p&gt;
&lt;p&gt;根据下面的说明： &lt;a href="//www.boost.org/doc/libs/1_42_0/doc/html/jam/building.html"&gt;//www.boost.org/doc/libs/1_42_0/doc/html/jam/building.html&lt;/a&gt;，用vcapp作为编译工具，也就是使用XL C++ 编译器文件集。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./bootstrap.sh --with-toolset&lt;span style="color:#f92672"&gt;=&lt;/span&gt;vacpp 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后使用&lt;code&gt;./b2&lt;/code&gt;编译，再用&lt;code&gt;./b2 install&lt;/code&gt;安装。&lt;/p&gt;</description></item><item><title>编译GRIB_API、Magics++和Metveiw</title><link>https://blog.perillaroc.wang/post/2013/2013-11-04-e7bc96e8af91grib_apie38081magicse5928cmetveiw/</link><pubDate>Mon, 04 Nov 2013 16:47:33 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-11-04-e7bc96e8af91grib_apie38081magicse5928cmetveiw/</guid><description/></item><item><title>Qt应用程序调用多个QMainwindow实例</title><link>https://blog.perillaroc.wang/post/2013/2013-10-31-qte5ba94e794a8e7a88be5ba8fe8b083e794a8e5a49ae4b8aaqmainwindowe5ae9ee4be8b/</link><pubDate>Thu, 31 Oct 2013 20:10:31 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-31-qte5ba94e794a8e7a88be5ba8fe8b083e794a8e5a49ae4b8aaqmainwindowe5ae9ee4be8b/</guid><description/></item><item><title>QT中的静态库项目</title><link>https://blog.perillaroc.wang/post/2013/2013-10-31-qte4b8ade79a84e99d99e68081e5ba93e9a1b9e79bae/</link><pubDate>Thu, 31 Oct 2013 20:10:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-31-qte4b8ade79a84e99d99e68081e5ba93e9a1b9e79bae/</guid><description/></item><item><title>QT自定义右键菜单</title><link>https://blog.perillaroc.wang/post/2013/2013-10-19-qte887aae5ae9ae4b989e58fb3e994aee88f9ce58d95/</link><pubDate>Sat, 19 Oct 2013 21:20:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-19-qte887aae5ae9ae4b989e58fb3e994aee88f9ce58d95/</guid><description/></item><item><title>突破防火墙封锁：使用Squid代理上网</title><link>https://blog.perillaroc.wang/post/2013/2013-10-13-use-squid-to-access-internet/</link><pubDate>Sun, 13 Oct 2013 16:24:47 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-13-use-squid-to-access-internet/</guid><description>&lt;p&gt;单位网关只限制访问外网 ip，不知道是何种方式探测有效 ip，估计会检测 MAC 地址，ip 地址与 MAC 地址绑定，只有有效 ip 地址并且安装赛门铁克定制版 SEP 软件才可以访问外网。
但 SEP 没提供 Linux 版本（定制版竟然没有多操作系统。。），想用 Linux 上网只能单独提出申请，太费劲。
只好在虚拟机中装 Linux 共享上网。
装好 Fedora，试过 NAT 方式、桥接方式，试过 Fedora 克隆 MAC 地址，均无法访问外网。
只好用我想到的最费劲的方式：架设代理服务器。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：现已更新为360天擎终端安全管理软件，并支持多种操作系统&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="1-获取squid-for-windows"&gt;1. 获取Squid For Windows&lt;/h2&gt;
&lt;p&gt;Squid 需要在 Cygwin 或 MinGW 环境中编译，参见官方 wiki《&lt;a href="//wiki.squid-cache.org/KnowledgeBase/Windows"&gt;Squid on Windows&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;另外 &lt;a href="//www.acmeconsulting.it/"&gt;Acme Consulting S.r.l.&lt;/a&gt;的&lt;a href="//wiki.squid-cache.org/GuidoSerassio"&gt;GuidoSerassio&lt;/a&gt; 提供了一个编译好的windows二进制包：&lt;a href="//squid.acmeconsulting.it/"&gt;Squid for Windows&lt;/a&gt;。
我使用其中的2.7版本。&lt;/p&gt;
&lt;h2 id="2-安装squid"&gt;2. 安装Squid&lt;/h2&gt;
&lt;p&gt;解压缩 Squid for Windows 到某目录，最好是配置文件的默认目录 &lt;code&gt;c:/squid&lt;/code&gt; 下，这样配置文件无需大范围改动，很适合我这种初学者。&lt;/p&gt;
&lt;p&gt;创建配置文件中提到的所有目录，其实只需创建 &lt;code&gt;/squid/var/cache&lt;/code&gt; 目录。&lt;/p&gt;
&lt;p&gt;进入 Squid 可执行程序目录&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;cd&lt;/span&gt; c:\squid\sbin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装 Squid 服务&lt;/p&gt;</description></item><item><title>编译Qt Oracle插件QT OCI</title><link>https://blog.perillaroc.wang/post/2013/2013-10-13-e7bc96e8af91qt-oraclee68f92e4bbb6qt-oci/</link><pubDate>Sun, 13 Oct 2013 16:14:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-13-e7bc96e8af91qt-oraclee68f92e4bbb6qt-oci/</guid><description/></item><item><title>Windows 7硬盘安装Ubuntu 13.04 64位双系统</title><link>https://blog.perillaroc.wang/post/2013/2013-10-08-windows-7e7a1ace79b98e5ae89e8a385ubuntu-13-04-64e4bd8de58f8ce7b3bbe7bb9f/</link><pubDate>Tue, 08 Oct 2013 16:38:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-08-windows-7e7a1ace79b98e5ae89e8a385ubuntu-13-04-64e4bd8de58f8ce7b3bbe7bb9f/</guid><description/></item><item><title>QFileSystemModel使用小结</title><link>https://blog.perillaroc.wang/post/2013/2013-10-08-qfilesystemmodele4bdbfe794a8e5b08fe7bb93/</link><pubDate>Tue, 08 Oct 2013 16:30:00 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-10-08-qfilesystemmodele4bdbfe794a8e5b08fe7bb93/</guid><description/></item><item><title>Qt Quick 2 学习资源</title><link>https://blog.perillaroc.wang/post/2013/2013-09-26-qt-quick-2-e5ada6e4b9a0e8b584e6ba90/</link><pubDate>Thu, 26 Sep 2013 15:42:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-09-26-qt-quick-2-e5ada6e4b9a0e8b584e6ba90/</guid><description>&lt;h2 id="入门示例"&gt;入门示例&lt;/h2&gt;
&lt;p&gt;《&lt;a href="//qt-project.org/doc/qt-5.1/qtquick/qml-tutorial.html"&gt;Hello world&lt;/a&gt;》&lt;/p&gt;
&lt;h2 id="qml-application-developer-resources"&gt;&lt;a href="//qt-project.org/doc/qt-5.1/qtdoc/qtquick-applicationdevelopers.html"&gt;QML Application Developer Resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2 id="qt-qml"&gt; Qt QML&lt;/h2&gt;
&lt;p&gt;&lt;a href="//qt-project.org/doc/qt-5.1/qtqml/qtqml-index.html"&gt;文档目录&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="qt-quick"&gt;Qt Quick&lt;/h2&gt;
&lt;p&gt;&lt;a href="//qt-project.org/doc/qt-5.1/qtquick/qtquick-index.html"&gt;文档目录&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Qt中Oracle数据库的DateTime类型</title><link>https://blog.perillaroc.wang/post/2013/2013-09-26-qte4b8adoraclee695b0e68daee5ba93e79a84datetimee7b1bbe59e8b/</link><pubDate>Thu, 26 Sep 2013 09:24:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-09-26-qte4b8adoraclee695b0e68daee5ba93e79a84datetimee7b1bbe59e8b/</guid><description/></item><item><title>QSqlQueryModel使用小结</title><link>https://blog.perillaroc.wang/post/2013/2013-09-26-qsqlquerymodele4bdbfe794a8e5b08fe7bb93/</link><pubDate>Thu, 26 Sep 2013 08:43:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-09-26-qsqlquerymodele4bdbfe794a8e5b08fe7bb93/</guid><description/></item><item><title>Qt Creator调试程序出错：RTTI symbol not found for class &amp;#039;QObject&amp;#039;</title><link>https://blog.perillaroc.wang/post/2013/2013-09-17-qt-creatore8b083e8af95e7a88be5ba8fe587bae99499efbc9artti-symbol-not-found-for-class-qobject/</link><pubDate>Tue, 17 Sep 2013 16:39:45 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-09-17-qt-creatore8b083e8af95e7a88be5ba8fe587bae99499efbc9artti-symbol-not-found-for-class-qobject/</guid><description/></item><item><title>QThread的一种用法</title><link>https://blog.perillaroc.wang/post/2013/2013-09-13-qthreade79a84e4b880e7a78de794a8e6b395/</link><pubDate>Fri, 13 Sep 2013 13:42:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-09-13-qthreade79a84e4b880e7a78de794a8e6b395/</guid><description/></item><item><title>获取Flickr图片URL地址</title><link>https://blog.perillaroc.wang/post/2013/2013-09-12-e88eb7e58f96flickre59bbee78987urle59cb0e59d80/</link><pubDate>Thu, 12 Sep 2013 14:12:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-09-12-e88eb7e58f96flickre59bbee78987urle59cb0e59d80/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>使用Alembic迁移数据库</title><link>https://blog.perillaroc.wang/post/2013/2013-08-30-e4bdbfe794a8alembice8bf81e7a7bbe695b0e68daee5ba93/</link><pubDate>Fri, 30 Aug 2013 01:11:31 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-30-e4bdbfe794a8alembice8bf81e7a7bbe695b0e68daee5ba93/</guid><description/></item><item><title>获取QT项目源码和编译目录</title><link>https://blog.perillaroc.wang/post/2013/2013-08-26-e88eb7e58f96qte9a1b9e79baee6ba90e7a081e5928ce7bc96e8af91e79baee5bd95/</link><pubDate>Mon, 26 Aug 2013 17:01:43 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-26-e88eb7e58f96qte9a1b9e79baee6ba90e7a081e5928ce7bc96e8af91e79baee5bd95/</guid><description/></item><item><title>SAE安装最新版Flask及Flask插件</title><link>https://blog.perillaroc.wang/post/2013/2013-08-26-saee5ae89e8a385e69c80e696b0e78988flaske58f8aflaske68f92e4bbb6/</link><pubDate>Mon, 26 Aug 2013 15:25:02 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-26-saee5ae89e8a385e69c80e696b0e78988flaske58f8aflaske68f92e4bbb6/</guid><description/></item><item><title>YAML格式简介(未完)</title><link>https://blog.perillaroc.wang/post/2013/2013-08-24-yamle6a0bce5bc8fe7ae80e4bb8be69caae5ae8c/</link><pubDate>Sat, 24 Aug 2013 19:29:35 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-24-yamle6a0bce5bc8fe7ae80e4bb8be69caae5ae8c/</guid><description/></item><item><title>Qt Creator中添加分裂器</title><link>https://blog.perillaroc.wang/post/2013/2013-08-20-qt-creatore4b8ade6b7bbe58aa0e58886e8a382e599a8/</link><pubDate>Tue, 20 Aug 2013 17:03:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-20-qt-creatore4b8ade6b7bbe58aa0e58886e8a382e599a8/</guid><description/></item><item><title>在QThread中使用QTimer</title><link>https://blog.perillaroc.wang/post/2013/2013-08-20-e59ca8qthreade4b8ade4bdbfe794a8qtimer/</link><pubDate>Tue, 20 Aug 2013 11:58:35 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-20-e59ca8qthreade4b8ade4bdbfe794a8qtimer/</guid><description/></item><item><title>[2013.08.16] 升级SAE WordPress博客</title><link>https://blog.perillaroc.wang/post/2013/2013-08-16-2013-08-16-e58d87e7baa7sae-wordpresse58d9ae5aea2/</link><pubDate>Fri, 16 Aug 2013 15:48:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-16-2013-08-16-e58d87e7baa7sae-wordpresse58d9ae5aea2/</guid><description/></item><item><title>QTableView与QStandardItemModel基本使用方法</title><link>https://blog.perillaroc.wang/post/2013/2013-08-15-qtableviewe4b88eqstandarditemmodele59fbae69cace4bdbfe794a8e696b9e6b395/</link><pubDate>Thu, 15 Aug 2013 17:02:47 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-15-qtableviewe4b88eqstandarditemmodele59fbae69cace4bdbfe794a8e696b9e6b395/</guid><description/></item><item><title>Qt使用libssh2库远程执行命令</title><link>https://blog.perillaroc.wang/post/2013/2013-08-11-qte4bdbfe794a8libssh2e5ba93e8bf9ce7a88be689a7e8a18ce591bde4bba4/</link><pubDate>Sun, 11 Aug 2013 22:27:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-11-qte4bdbfe794a8libssh2e5ba93e8bf9ce7a88be689a7e8a18ce591bde4bba4/</guid><description/></item><item><title>linux安装git服务器gitolite</title><link>https://blog.perillaroc.wang/post/2013/2013-08-11-linuxe5ae89e8a385gite69c8de58aa1e599a8gitolite/</link><pubDate>Sun, 11 Aug 2013 22:13:13 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-11-linuxe5ae89e8a385gite69c8de58aa1e599a8gitolite/</guid><description/></item><item><title>Windows 7下VS2010编译libssh2</title><link>https://blog.perillaroc.wang/post/2013/2013-08-11-windows-7e4b88bvs2010e7bc96e8af91libssh2/</link><pubDate>Sun, 11 Aug 2013 10:46:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-11-windows-7e4b88bvs2010e7bc96e8af91libssh2/</guid><description/></item><item><title>linux获取用户信息</title><link>https://blog.perillaroc.wang/post/2013/2013-08-09-linuxe88eb7e58f96e794a8e688b7e4bfa1e681af/</link><pubDate>Fri, 09 Aug 2013 14:53:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-09-linuxe88eb7e58f96e794a8e688b7e4bfa1e681af/</guid><description/></item><item><title>LoadLeveler基本使用说明</title><link>https://blog.perillaroc.wang/post/2013/2013-08-06-loadleveler-getting-started/</link><pubDate>Tue, 06 Aug 2013 17:15:32 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-06-loadleveler-getting-started/</guid><description>&lt;p&gt;单位业务系统使用LoadLeveler管理作业。运行环境、使用脚本都已经配置好，一般只使用命令行命令。&lt;/p&gt;
&lt;h2 id="loadleveler基本命令"&gt;LoadLeveler基本命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;llsubmit&lt;/code&gt;: 提交作业&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llq&lt;/code&gt;: 显示作业状态&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llcancel&lt;/code&gt;: 取消作业&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llcancel -user&lt;/code&gt;: 取消一个用户的作业&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llstatus&lt;/code&gt;: 显示节点状态&lt;/li&gt;
&lt;li&gt;&lt;code&gt;llclass&lt;/code&gt;: 查看信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;### llsubmit 提交作业&lt;/p&gt;
&lt;p&gt;SMS系统中提交作业用封装好的&lt;code&gt;llsubmit2&lt;/code&gt;脚本，还没用过。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/ksh 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;\#&lt;/span&gt; llsubmit2 jobname taskname &lt;span style="color:#75715e"&gt;## host &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -ex 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SUBMITLOG&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$WORKDIR/sublog/submit.log 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;test -d $WORKDIR/sublog &lt;span style="color:#f92672"&gt;||&lt;/span&gt;mkdir -p $WORKDIR/sublog 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export SUBMITLOG 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; $# -ne &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; ; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &amp;amp;&lt;span style="color:#75715e"&gt;#8230; &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jobname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$1 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;taskname&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$2 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#echo $jobname $taskname &amp;gt;&amp;gt;$SUBMITLOG &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;\#&lt;/span&gt; host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$2 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;\#&lt;/span&gt; host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sp04n01 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;\#&lt;/span&gt; rsh $host llsubmit &amp;amp;&lt;span style="color:#75715e"&gt;#8211; &amp;lt; $jobname &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $USER &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nwp &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; ; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nameofsms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nwpc_op 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $USER &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nwp_qu &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; ; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nameofsms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nwpc_qu 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $USER &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nwp_sp &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; ; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nameofsms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nwpc_sp 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $USER &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nwp_ex &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; ; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nameofsms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nwpc_ex 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $USER &lt;span style="color:#f92672"&gt;=&lt;/span&gt; nwp_xp &lt;span style="color:#f92672"&gt;]]&lt;/span&gt; ; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nameofsms&lt;span style="color:#f92672"&gt;=&lt;/span&gt;nwpc_xp 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;llsubmit $jobname 2&amp;gt;&amp;gt;$SUBMITLOG&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;echo $name | cut -d &amp;amp;&lt;span style="color:#75715e"&gt;#8216;&amp;#34;&amp;amp;#8217; -f 2) &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cdp &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt;EOF 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;login $nameofsms $USER 1 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;alter -v $taskname SMSRID $rid 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;exit 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;EOF&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#rsh llq &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="llq-显示作业状态"&gt;llq 显示作业状态&lt;/h3&gt;
&lt;p&gt;llq 列出队列中的任务&lt;/p&gt;</description></item><item><title>Qt XML DOM方式读写</title><link>https://blog.perillaroc.wang/post/2013/2013-08-04-qt-xml-dome696b9e5bc8fe8afbbe58699/</link><pubDate>Sun, 04 Aug 2013 11:54:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-04-qt-xml-dome696b9e5bc8fe8afbbe58699/</guid><description/></item><item><title>Qt 窗口大小自动变化</title><link>https://blog.perillaroc.wang/post/2013/2013-08-01-qt-auto-resize-window/</link><pubDate>Thu, 01 Aug 2013 14:03:18 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-08-01-qt-auto-resize-window/</guid><description>&lt;p&gt;界面中需要隐藏不常用的设置项，并通过按钮来控制是否显示。窗口大小随控件的隐藏和显示而自动变化。&lt;/p&gt;
&lt;p&gt;Qt中的布局管理器（各种Layout类）可以自动管理控件布局，只需将控件添加到各种Layout中，就可以实现布局。
各个Layout类默认随父控件大小变化而变化，就像我们放大窗口，里面控件也会随之拉伸一样。这种关系是父控件变化导致子控件变化。&lt;/p&gt;
&lt;p&gt;而我需要的是控件隐藏时，窗口变小，与上面相反，由子控件大小控制父控件大小。&lt;/p&gt;
&lt;p&gt;这就需要用到&lt;code&gt;QLayout::SetFixedSize&lt;/code&gt;（Layout中主控件大小为sizeHint()，不可放大缩小）。设置为SetFixedSize后，窗口大小固定，仅由内部控件大小决定，窗口没有最大化按钮，也不能拖拽缩放。这样，控件隐藏时，窗口重新计算自己的大小，并自动缩小，反之亦然。&lt;/p&gt;
&lt;h2 id="界面"&gt;界面&lt;/h2&gt;
&lt;p&gt;用More按钮（设置为checkable）控制两个GroupBox是否显示，并将More的&lt;code&gt;toggled(bool)&lt;/code&gt;信号与GroupBox的&lt;code&gt;setShown(bool)&lt;/code&gt;槽连接。&lt;/p&gt;
&lt;p&gt;如下图所示&lt;/p&gt;
&lt;img class="alignnone" title="GET Gui 信号与槽" src="http://ww4.sinaimg.cn/large/4afdac38jw1e774mhaug0j20eg08sq3v.jpg" alt="GET Gui 信号与槽" width="520" height="316" /&gt;
&lt;h2 id="代码"&gt;代码&lt;/h2&gt;
&lt;p&gt;在构造函数中设置size constraint，并隐藏不显示的控件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ui&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;gb_switch_more&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;hide(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ui&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;gb_address_more&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;hide(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout()&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setSizeConstraint(QLayout&lt;span style="color:#f92672"&gt;::&lt;/span&gt;SetFixedSize); 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="效果"&gt;效果&lt;/h2&gt;
&lt;p&gt;初始&lt;/p&gt;
&lt;img class="alignnone" title="GET Gui" src="http://ww1.sinaimg.cn/large/4afdac38jw1e774dl2cp9j20fe0gf0ue.jpg" alt="" width="554" height="591" /&gt; 
&lt;p&gt;点击More之后&lt;/p&gt;
&lt;img class="alignnone" title="GET Gui" src="http://ww3.sinaimg.cn/large/4afdac38jw1e774dnjzcbj20fe0lrmzi.jpg" alt="" width="554" height="783" /&gt;</description></item><item><title>Qt SQLite 批量插入优化</title><link>https://blog.perillaroc.wang/post/2013/2013-06-27-qt-sqlite-e689b9e9878fe68f92e585a5e4bc98e58c96/</link><pubDate>Thu, 27 Jun 2013 16:01:42 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-06-27-qt-sqlite-e689b9e9878fe68f92e585a5e4bc98e58c96/</guid><description/></item><item><title>Qt单元测试库QTestLib</title><link>https://blog.perillaroc.wang/post/2013/2013-06-08-qte58d95e58583e6b58be8af95e5ba93qtestlib/</link><pubDate>Sat, 08 Jun 2013 09:27:30 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-06-08-qte58d95e58583e6b58be8af95e5ba93qtestlib/</guid><description/></item><item><title>Qt项目设置</title><link>https://blog.perillaroc.wang/post/2013/2013-06-07-qte9a1b9e79baee8aebee7bdae/</link><pubDate>Fri, 07 Jun 2013 16:54:49 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-06-07-qte9a1b9e79baee8aebee7bdae/</guid><description/></item><item><title>Python2.7 安装 MySQL-python-1.2.3模块</title><link>https://blog.perillaroc.wang/post/2013/2013-05-28-python2-7-e5ae89e8a385-mysql-python-1-2-3e6a8a1e59d97/</link><pubDate>Tue, 28 May 2013 22:35:53 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-05-28-python2-7-e5ae89e8a385-mysql-python-1-2-3e6a8a1e59d97/</guid><description/></item><item><title>Flask学习笔记(1) 安装Flask(Windows 7)</title><link>https://blog.perillaroc.wang/post/2013/2013-05-27-flaske5ada6e4b9a0e7ac94e8aeb01-e5ae89e8a385flaskwindows-7/</link><pubDate>Mon, 27 May 2013 14:51:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-05-27-flaske5ada6e4b9a0e7ac94e8aeb01-e5ae89e8a385flaskwindows-7/</guid><description/></item><item><title>Qt遍历控件</title><link>https://blog.perillaroc.wang/post/2013/2013-05-20-qte9818de58e86e68ea7e4bbb6/</link><pubDate>Mon, 20 May 2013 10:10:38 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-05-20-qte9818de58e86e68ea7e4bbb6/</guid><description/></item><item><title>Qt创建翻译文件</title><link>https://blog.perillaroc.wang/post/2013/2013-05-20-qte5889be5bbbae7bfbbe8af91e69687e4bbb6/</link><pubDate>Mon, 20 May 2013 09:10:54 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-05-20-qte5889be5bbbae7bfbbe8af91e69687e4bbb6/</guid><description/></item><item><title>Qt Creator编译器、调试器配置</title><link>https://blog.perillaroc.wang/post/2013/2013-05-14-qtcreatore7bc96e8af91e599a8e38081e8b083e8af95e599a8e9858de7bdae/</link><pubDate>Tue, 14 May 2013 08:45:49 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-05-14-qtcreatore7bc96e8af91e599a8e38081e8b083e8af95e599a8e9858de7bdae/</guid><description/></item><item><title>SMS学习笔记5 变量</title><link>https://blog.perillaroc.wang/post/2013/2013-05-02-smse5ada6e4b9a0e7ac94e8aeb05-e58f98e9878f/</link><pubDate>Thu, 02 May 2013 14:11:42 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-05-02-smse5ada6e4b9a0e7ac94e8aeb05-e58f98e9878f/</guid><description/></item><item><title>FTP上传整个目录</title><link>https://blog.perillaroc.wang/post/2013/2013-04-25-ftpe4b88ae4bca0e695b4e4b8aae79baee5bd95/</link><pubDate>Thu, 25 Apr 2013 16:21:43 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-04-25-ftpe4b88ae4bca0e695b4e4b8aae79baee5bd95/</guid><description/></item><item><title>SMS学习笔记4 SMS预处理器</title><link>https://blog.perillaroc.wang/post/2013/2013-04-23-smse5ada6e4b9a0e7ac94e8aeb04-smse9a284e5a484e79086e599a8/</link><pubDate>Tue, 23 Apr 2013 15:35:42 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-04-23-smse5ada6e4b9a0e7ac94e8aeb04-smse9a284e5a484e79086e599a8/</guid><description/></item><item><title>SMS学习笔记3 使用SMS</title><link>https://blog.perillaroc.wang/post/2013/2013-04-23-smse5ada6e4b9a0e7ac94e8aeb03/</link><pubDate>Tue, 23 Apr 2013 11:20:52 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-04-23-smse5ada6e4b9a0e7ac94e8aeb03/</guid><description/></item><item><title>SMS学习笔记2 运行SMS</title><link>https://blog.perillaroc.wang/post/2013/2013-04-23-smse5ada6e4b9a0e7ac94e8aeb02/</link><pubDate>Tue, 23 Apr 2013 08:41:51 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-04-23-smse5ada6e4b9a0e7ac94e8aeb02/</guid><description/></item><item><title>VMware虚拟机共享主机IP上网</title><link>https://blog.perillaroc.wang/post/2013/2013-04-08-vmwaree8999ae68b9fe69cbae585b1e4baabe4b8bbe69cbaipe4b88ae7bd91/</link><pubDate>Mon, 08 Apr 2013 14:24:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-04-08-vmwaree8999ae68b9fe69cbae585b1e4baabe4b8bbe69cbaipe4b88ae7bd91/</guid><description/></item><item><title>[转载] 使用VC/MFC的优秀开源项目</title><link>https://blog.perillaroc.wang/post/2013/2013-03-27-e8bdace8bdbd-e4bdbfe794a8vcmfce79a84e4bc98e7a780e5bc80e6ba90e9a1b9e79bae/</link><pubDate>Wed, 27 Mar 2013 23:09:02 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-03-27-e8bdace8bdbd-e4bdbfe794a8vcmfce79a84e4bc98e7a780e5bc80e6ba90e9a1b9e79bae/</guid><description/></item><item><title>安装MySQL、Apache HTTP Server和PHP（Windows 7）</title><link>https://blog.perillaroc.wang/post/2013/2013-01-09-e5ae89e8a385mysqle38081apache-http-servere5928cphpefbc88windows-7efbc89/</link><pubDate>Wed, 09 Jan 2013 20:46:17 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2013/2013-01-09-e5ae89e8a385mysqle38081apache-http-servere5928cphpefbc88windows-7efbc89/</guid><description/></item><item><title>C++日期时间函数</title><link>https://blog.perillaroc.wang/post/2012/2012-12-18-ce697a5e69c9fe697b6e997b4e587bde695b0/</link><pubDate>Tue, 18 Dec 2012 20:14:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-12-18-ce697a5e69c9fe697b6e997b4e587bde695b0/</guid><description/></item><item><title>[11.18] 被鄙视的新浪笔试</title><link>https://blog.perillaroc.wang/post/2012/2012-11-18-11-18-e8a2abe98499e8a786e79a84e696b0e6b5aae7ac94e8af95/</link><pubDate>Sun, 18 Nov 2012 20:50:49 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-11-18-11-18-e8a2abe98499e8a786e79a84e696b0e6b5aae7ac94e8af95/</guid><description/></item><item><title>[10.16] 某兰面试</title><link>https://blog.perillaroc.wang/post/2012/2012-10-17-10-16-e69f90e585b0e99da2e8af95/</link><pubDate>Wed, 17 Oct 2012 16:44:32 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-10-17-10-16-e69f90e585b0e99da2e8af95/</guid><description/></item><item><title>[10.13] 某艺笔试题</title><link>https://blog.perillaroc.wang/post/2012/2012-10-17-10-13-e69f90e889bae7ac94e8af95e9a298/</link><pubDate>Wed, 17 Oct 2012 16:30:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-10-17-10-13-e69f90e889bae7ac94e8af95e9a298/</guid><description/></item><item><title>[10.12] 某科技Web研发工程师笔试</title><link>https://blog.perillaroc.wang/post/2012/2012-10-12-10-12-e69f90e7a791e68a80webe7a094e58f91e5b7a5e7a88be5b888e7ac94e8af95/</link><pubDate>Fri, 12 Oct 2012 21:13:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-10-12-10-12-e69f90e7a791e68a80webe7a094e58f91e5b7a5e7a88be5b888e7ac94e8af95/</guid><description/></item><item><title>[10.10] 和协航电笔试</title><link>https://blog.perillaroc.wang/post/2012/2012-10-10-10-10-e5928ce58d8fe888aae794b5e7ac94e8af95/</link><pubDate>Wed, 10 Oct 2012 22:40:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-10-10-10-10-e5928ce58d8fe888aae794b5e7ac94e8af95/</guid><description/></item><item><title>[10.10] 优酷土豆笔试</title><link>https://blog.perillaroc.wang/post/2012/2012-10-10-e4bc98e985b7e59c9fe8b186e7ac94e8af95/</link><pubDate>Wed, 10 Oct 2012 21:49:40 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-10-10-e4bc98e985b7e59c9fe8b186e7ac94e8af95/</guid><description/></item><item><title>数码视讯面试</title><link>https://blog.perillaroc.wang/post/2012/2012-09-26-e695b0e7a081e8a786e8aeafe99da2e8af95/</link><pubDate>Wed, 26 Sep 2012 20:28:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-09-26-e695b0e7a081e8a786e8aeafe99da2e8af95/</guid><description/></item><item><title>Windows下安装Nginx和PHP</title><link>https://blog.perillaroc.wang/post/2012/2012-08-31-windowse4b88be5ae89e8a385nginxe5928cphp/</link><pubDate>Fri, 31 Aug 2012 13:09:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-08-31-windowse4b88be5ae89e8a385nginxe5928cphp/</guid><description/></item><item><title>GitHub学习资料</title><link>https://blog.perillaroc.wang/post/2012/2012-08-27-githube5ada6e4b9a0e8b584e69699/</link><pubDate>Mon, 27 Aug 2012 13:07:17 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-08-27-githube5ada6e4b9a0e8b584e69699/</guid><description/></item><item><title>[转载][北邮人]怎样花两月时间去应聘互联网公司</title><link>https://blog.perillaroc.wang/post/2012/2012-08-27-e8bdace8bdbde58c97e982aee4babae6808ee6a0b7e88ab1e4b8a4e69c88e697b6e997b4e58ebbe5ba94e88198e4ba92e88194e7bd91e585ace58fb8/</link><pubDate>Mon, 27 Aug 2012 12:23:52 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-08-27-e8bdace8bdbde58c97e982aee4babae6808ee6a0b7e88ab1e4b8a4e69c88e697b6e997b4e58ebbe5ba94e88198e4ba92e88194e7bd91e585ace58fb8/</guid><description/></item><item><title>VideoCapture：OpenCV的读视频类</title><link>https://blog.perillaroc.wang/post/2012/2012-08-23-videocaptureefbc9aopencve79a84e8afbbe8a786e9a291e7b1bb/</link><pubDate>Thu, 23 Aug 2012 21:38:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-08-23-videocaptureefbc9aopencve79a84e8afbbe8a786e9a291e7b1bb/</guid><description/></item><item><title>OpenCV坐标方向</title><link>https://blog.perillaroc.wang/post/2012/2012-08-02-opencve59d90e6a087e696b9e59091/</link><pubDate>Thu, 02 Aug 2012 23:07:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-08-02-opencve59d90e6a087e696b9e59091/</guid><description/></item><item><title>一个简单的C++计时器</title><link>https://blog.perillaroc.wang/post/2012/2012-07-05-e4b880e4b8aae7ae80e58d95e79a84ce8aea1e697b6e599a8/</link><pubDate>Thu, 05 Jul 2012 14:03:47 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-07-05-e4b880e4b8aae7ae80e58d95e79a84ce8aea1e697b6e599a8/</guid><description/></item><item><title>OpenCV中矩阵的归一化</title><link>https://blog.perillaroc.wang/post/2012/2012-06-30-opencve4b8ade79fa9e998b5e79a84e5bd92e4b880e58c96/</link><pubDate>Sat, 30 Jun 2012 21:05:45 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-30-opencve4b8ade79fa9e998b5e79a84e5bd92e4b880e58c96/</guid><description/></item><item><title>VC++编译中出现的几个警告</title><link>https://blog.perillaroc.wang/post/2012/2012-06-29-vce7bc96e8af91e4b8ade587bae78eb0e79a84e587a0e4b8aae8ada6e5918a/</link><pubDate>Fri, 29 Jun 2012 00:10:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-29-vce7bc96e8af91e4b8ade587bae78eb0e79a84e587a0e4b8aae8ada6e5918a/</guid><description/></item><item><title>OpenCV学习笔记（一）：读取、显示、保存图片</title><link>https://blog.perillaroc.wang/post/2012/2012-06-28-opencve5ada6e4b9a0e7ac94e8aeb0efbc88e4b880efbc89efbc9ae8afbbe58f96e38081e698bee7a4bae38081e4bf9de5ad98e59bbee78987/</link><pubDate>Thu, 28 Jun 2012 01:13:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-28-opencve5ada6e4b9a0e7ac94e8aeb0efbc88e4b880efbc89efbc9ae8afbbe58f96e38081e698bee7a4bae38081e4bf9de5ad98e59bbee78987/</guid><description/></item><item><title>OpenCV学习笔记（零）：安装与编译</title><link>https://blog.perillaroc.wang/post/2012/2012-06-26-opencve5ada6e4b9a0e7ac94e8aeb0efbc88e99bb6efbc89efbc9ae5ae89e8a385e4b88ee7bc96e8af91/</link><pubDate>Tue, 26 Jun 2012 16:49:18 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-26-opencve5ada6e4b9a0e7ac94e8aeb0efbc88e99bb6efbc89efbc9ae5ae89e8a385e4b88ee7bc96e8af91/</guid><description/></item><item><title>HTC G11 刷国行Adroid 4.0系统</title><link>https://blog.perillaroc.wang/post/2012/2012-06-25-htc-g11-e588b7e59bbde8a18cadroid-4-0e7b3bbe7bb9f/</link><pubDate>Mon, 25 Jun 2012 19:54:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-25-htc-g11-e588b7e59bbde8a18cadroid-4-0e7b3bbe7bb9f/</guid><description/></item><item><title>《Google C++ 风格指南》阅读笔记</title><link>https://blog.perillaroc.wang/post/2012/2012-06-20-e3808agoogle-c-e9a38ee6a0bce68c87e58d97e3808be99885e8afbbe7ac94e8aeb0/</link><pubDate>Wed, 20 Jun 2012 15:13:28 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-20-e3808agoogle-c-e9a38ee6a0bce68c87e58d97e3808be99885e8afbbe7ac94e8aeb0/</guid><description/></item><item><title>数字图像处理笔记（三）：Color</title><link>https://blog.perillaroc.wang/post/2012/2012-06-11-e695b0e5ad97e59bbee5838fe5a484e79086e7ac94e8aeb0e4b889efbc9acolor/</link><pubDate>Mon, 11 Jun 2012 09:20:38 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-11-e695b0e5ad97e59bbee5838fe5a484e79086e7ac94e8aeb0e4b889efbc9acolor/</guid><description/></item><item><title>[2012.06.08] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-06-11-2012-06-08-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</link><pubDate>Mon, 11 Jun 2012 09:15:11 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-11-2012-06-08-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</guid><description/></item><item><title>数字图像处理笔记（二）：Point Operations</title><link>https://blog.perillaroc.wang/post/2012/2012-06-08-e695b0e5ad97e59bbee5838fe5a484e79086e7ac94e8aeb0e4ba8cefbc9apoint-operations/</link><pubDate>Fri, 08 Jun 2012 11:10:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-08-e695b0e5ad97e59bbee5838fe5a484e79086e7ac94e8aeb0e4ba8cefbc9apoint-operations/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>利用边框实现网页导航栏的动态效果</title><link>https://blog.perillaroc.wang/post/2012/2012-06-07-e7bd91e9a1b5e5afbce888aae6a08fe588a9e794a8e8beb9e6a186e5ae9ee78eb0e58aa8e68081e69588e69e9c/</link><pubDate>Thu, 07 Jun 2012 08:49:53 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-07-e7bd91e9a1b5e5afbce888aae6a08fe588a9e794a8e8beb9e6a186e5ae9ee78eb0e58aa8e68081e69588e69e9c/</guid><description/></item><item><title>简单的jquery对话框</title><link>https://blog.perillaroc.wang/post/2012/2012-06-06-e7ae80e58d95e79a84jquerye5afb9e8af9de6a186/</link><pubDate>Wed, 06 Jun 2012 20:41:49 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-06-e7ae80e58d95e79a84jquerye5afb9e8af9de6a186/</guid><description/></item><item><title>简单学习Twitter网页布局的笔记</title><link>https://blog.perillaroc.wang/post/2012/2012-06-02-e7ae80e58d95e5ada6e4b9a0twittere7bd91e9a1b5e5b883e5b180e79a84e7ac94e8aeb0/</link><pubDate>Sat, 02 Jun 2012 19:07:19 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-02-e7ae80e58d95e5ada6e4b9a0twittere7bd91e9a1b5e5b883e5b180e79a84e7ac94e8aeb0/</guid><description/></item><item><title>[音频格式] WAV音频格式</title><link>https://blog.perillaroc.wang/post/2012/2012-06-02-e99fb3e9a291e6a0bce5bc8f-wave99fb3e9a291e6a0bce5bc8f/</link><pubDate>Sat, 02 Jun 2012 15:28:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-02-e99fb3e9a291e6a0bce5bc8f-wave99fb3e9a291e6a0bce5bc8f/</guid><description/></item><item><title>[2012.06.01] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-06-02-2012-06-01-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</link><pubDate>Sat, 02 Jun 2012 15:25:49 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-06-02-2012-06-01-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</guid><description/></item><item><title>几个方便上网的小项目</title><link>https://blog.perillaroc.wang/post/2012/2012-05-25-e587a0e4b8aae696b9e4bebfe4b88ae7bd91e79a84e5b08fe9a1b9e79bae/</link><pubDate>Fri, 25 May 2012 22:20:40 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-25-e587a0e4b8aae696b9e4bebfe4b88ae7bd91e79a84e5b08fe9a1b9e79bae/</guid><description/></item><item><title>[TICPP] 设计模式学习笔记</title><link>https://blog.perillaroc.wang/post/2012/2012-05-21-ticpp-e8aebee8aea1e6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb0/</link><pubDate>Mon, 21 May 2012 15:28:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-21-ticpp-e8aebee8aea1e6a8a1e5bc8fe5ada6e4b9a0e7ac94e8aeb0/</guid><description/></item><item><title>C语言的动态内存管理</title><link>https://blog.perillaroc.wang/post/2012/2012-05-20-ce8afade8a880e79a84e58aa8e68081e58685e5ad98e7aea1e79086/</link><pubDate>Sun, 20 May 2012 23:55:11 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-20-ce8afade8a880e79a84e58aa8e68081e58685e5ad98e7aea1e79086/</guid><description/></item><item><title>[图像格式] BMP（BitMap）</title><link>https://blog.perillaroc.wang/post/2012/2012-05-19-e59bbee5838fe6a0bce5bc8f-bmpefbc88bitmapefbc89/</link><pubDate>Sat, 19 May 2012 23:00:10 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-19-e59bbee5838fe6a0bce5bc8f-bmpefbc88bitmapefbc89/</guid><description/></item><item><title>大唐高鸿笔试题</title><link>https://blog.perillaroc.wang/post/2012/2012-05-16-e5a4a7e59490e9ab98e9b8bfe7ac94e8af95e9a298/</link><pubDate>Wed, 16 May 2012 23:09:30 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-16-e5a4a7e59490e9ab98e9b8bfe7ac94e8af95e9a298/</guid><description>&lt;p style="text-align: right;"&gt;</description></item><item><title>人民搜索笔试</title><link>https://blog.perillaroc.wang/post/2012/2012-05-16-e4babae6b091e6909ce7b4a2e7ac94e8af95/</link><pubDate>Wed, 16 May 2012 22:51:27 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-16-e4babae6b091e6909ce7b4a2e7ac94e8af95/</guid><description>&lt;p style="text-align: right;"&gt;</description></item><item><title>方正电子的面试</title><link>https://blog.perillaroc.wang/post/2012/2012-05-16-e696b9e6ada3e794b5e5ad90e79a84e4b88ae69cbae9a298/</link><pubDate>Wed, 16 May 2012 22:32:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-05-16-e696b9e6ada3e794b5e5ad90e79a84e4b88ae69cbae9a298/</guid><description>&lt;p style="text-align: right;"&gt;</description></item><item><title>数据结构——优先队列（堆）</title><link>https://blog.perillaroc.wang/post/2012/2012-04-22-e695b0e68daee7bb93e69e84-e4bc98e58588e9989fe58897efbc88e5a086efbc89/</link><pubDate>Sun, 22 Apr 2012 15:10:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-04-22-e695b0e68daee7bb93e69e84-e4bc98e58588e9989fe58897efbc88e5a086efbc89/</guid><description/></item><item><title>找实习前需要学习的一些专业知识</title><link>https://blog.perillaroc.wang/post/2012/2012-04-15-e689bee5ae9ee4b9a0e5898de99c80e8a681e5ada6e4b9a0e79a84e4b880e4ba9be4b893e4b89ae79fa5e8af86/</link><pubDate>Sun, 15 Apr 2012 16:49:07 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-04-15-e689bee5ae9ee4b9a0e5898de99c80e8a681e5ada6e4b9a0e79a84e4b880e4ba9be4b893e4b89ae79fa5e8af86/</guid><description/></item><item><title>跨域请求</title><link>https://blog.perillaroc.wang/post/2012/2012-04-02-e8b7a8e59f9fe8afb7e6b182/</link><pubDate>Mon, 02 Apr 2012 19:07:05 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-04-02-e8b7a8e59f9fe8afb7e6b182/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>PHP中使用cURL库模拟网络通信</title><link>https://blog.perillaroc.wang/post/2012/2012-04-02-phpe4b8ade4bdbfe794a8curle5ba93e6a8a1e68b9fe7bd91e7bb9ce9809ae4bfa1/</link><pubDate>Mon, 02 Apr 2012 18:40:36 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-04-02-phpe4b8ade4bdbfe794a8curle5ba93e6a8a1e68b9fe7bd91e7bb9ce9809ae4bfa1/</guid><description/></item><item><title>几个网站开放平台的帮助文档</title><link>https://blog.perillaroc.wang/post/2012/2012-03-31-e587a0e4b8aae7bd91e7ab99e5bc80e694bee5b9b3e58fb0e79a84e5b8aee58aa9e69687e6a1a3/</link><pubDate>Sat, 31 Mar 2012 15:53:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-31-e587a0e4b8aae7bd91e7ab99e5bc80e694bee5b9b3e58fb0e79a84e5b8aee58aa9e69687e6a1a3/</guid><description/></item><item><title>短网址API</title><link>https://blog.perillaroc.wang/post/2012/2012-03-31-e79fade7bd91e59d80api/</link><pubDate>Sat, 31 Mar 2012 15:47:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-31-e79fade7bd91e59d80api/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>PHP代码分析文档生成软件</title><link>https://blog.perillaroc.wang/post/2012/2012-03-24-phpe4bba3e7a081e58886e69e90e69687e6a1a3e7949fe68890e8bdafe4bbb6/</link><pubDate>Sat, 24 Mar 2012 00:38:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-24-phpe4bba3e7a081e58886e69e90e69687e6a1a3e7949fe68890e8bdafe4bbb6/</guid><description/></item><item><title>处理JSON数据</title><link>https://blog.perillaroc.wang/post/2012/2012-03-23-e5a484e79086jsone695b0e68dae/</link><pubDate>Fri, 23 Mar 2012 22:13:07 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-23-e5a484e79086jsone695b0e68dae/</guid><description/></item><item><title>人人开放平台API网站接入的简单使用</title><link>https://blog.perillaroc.wang/post/2012/2012-03-17-e4babae4babae5bc80e694bee5b9b3e58fb0apie7bd91e7ab99e68ea5e585a5e79a84e7ae80e58d95e4bdbfe794a8/</link><pubDate>Sat, 17 Mar 2012 15:16:31 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-17-e4babae4babae5bc80e694bee5b9b3e58fb0apie7bd91e7ab99e68ea5e585a5e79a84e7ae80e58d95e4bdbfe794a8/</guid><description/></item><item><title>配置Apache HTTP Server、PHP与MySQL</title><link>https://blog.perillaroc.wang/post/2012/2012-03-04-e9858de7bdaeapache-http-server_phpe4b88emysql/</link><pubDate>Sun, 04 Mar 2012 13:11:26 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-04-e9858de7bdaeapache-http-server_phpe4b88emysql/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>某c++代码从linux移植到windows的笔记</title><link>https://blog.perillaroc.wang/post/2012/2012-03-03-e69f90cppe4bba3e7a081e4bb8elinuxe7a7bbe6a48de588b0windowse79a84e7ac94e8aeb0/</link><pubDate>Sat, 03 Mar 2012 15:50:33 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-03-e69f90cppe4bba3e7a081e4bb8elinuxe7a7bbe6a48de588b0windowse79a84e7ac94e8aeb0/</guid><description/></item><item><title>PHP中处理用户提交的信息</title><link>https://blog.perillaroc.wang/post/2012/2012-03-03-phpe4b8ade5a484e79086e794a8e688b7e68f90e4baa4e79a84e4bfa1e681af/</link><pubDate>Sat, 03 Mar 2012 15:41:58 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-03-phpe4b8ade5a484e79086e794a8e688b7e68f90e4baa4e79a84e4bfa1e681af/</guid><description>&lt;p&gt;时刻牢记下面的原则：&lt;/p&gt;
&lt;p style="text-align: center;"&gt;
 &lt;span style="color: #ff0000;"&gt;&lt;strong&gt;不要信任用户输入的任何内容&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="text-align: center;"&gt;
 &lt;p&gt;</description></item><item><title>G11刷机之路</title><link>https://blog.perillaroc.wang/post/2012/2012-03-03-g11e588b7e69cbae4b98be8b7af/</link><pubDate>Sat, 03 Mar 2012 13:49:24 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-03-03-g11e588b7e69cbae4b98be8b7af/</guid><description/></item><item><title>OpenCV中构造Mat矩阵赋值和复制的花销</title><link>https://blog.perillaroc.wang/post/2012/2012-02-27-opencve4b8ade69e84e980a0mate79fa9e998b5e8b58be580bce5928ce5a48de588b6e79a84e88ab1e99480/</link><pubDate>Mon, 27 Feb 2012 20:49:16 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-27-opencve4b8ade69e84e980a0mate79fa9e998b5e8b58be580bce5928ce5a48de588b6e79a84e88ab1e99480/</guid><description/></item><item><title>PHP中的POSIX Extended正则表达式</title><link>https://blog.perillaroc.wang/post/2012/2012-02-18-phpe4b8ade79a84posix-extendede6ada3e58899e8a1a8e8bebee5bc8f/</link><pubDate>Sat, 18 Feb 2012 13:28:48 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-18-phpe4b8ade79a84posix-extendede6ada3e58899e8a1a8e8bebee5bc8f/</guid><description/></item><item><title>[转载] 计算机视觉研究群体及专家主页汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-02-14-e8bdace8bdbd-e8aea1e7ae97e69cbae8a786e8a789e7a094e7a9b6e7bea4e4bd93e58f8ae4b893e5aeb6e4b8bbe9a1b5e6b187e680bb/</link><pubDate>Tue, 14 Feb 2012 12:52:29 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-14-e8bdace8bdbd-e8aea1e7ae97e69cbae8a786e8a789e7a094e7a9b6e7bea4e4bd93e58f8ae4b893e5aeb6e4b8bbe9a1b5e6b187e680bb/</guid><description/></item><item><title>[转载] 计算机视觉资料链接</title><link>https://blog.perillaroc.wang/post/2012/2012-02-14-e8bdace8bdbd-e8aea1e7ae97e69cbae8a786e8a789e8b584e69699e993bee68ea5/</link><pubDate>Tue, 14 Feb 2012 12:47:12 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-14-e8bdace8bdbd-e8aea1e7ae97e69cbae8a786e8a789e8b584e69699e993bee68ea5/</guid><description/></item><item><title>google code上几个图形学相关的项目</title><link>https://blog.perillaroc.wang/post/2012/2012-02-10-google-codee4b88ae587a0e4b8aae59bbee5bda2e5ada6e79bb8e585b3e79a84e9a1b9e79bae/</link><pubDate>Fri, 10 Feb 2012 15:20:32 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-10-google-codee4b88ae587a0e4b8aae59bbee5bda2e5ada6e79bb8e585b3e79a84e9a1b9e79bae/</guid><description>&lt;p&gt;[&lt;/p&gt;</description></item><item><title>[2011.09.02] 实验室讨论班汇总（未完）</title><link>https://blog.perillaroc.wang/post/2012/2012-02-08-2011-09-02-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bbefbc88e69caae5ae8cefbc89/</link><pubDate>Wed, 08 Feb 2012 16:13:50 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-08-2011-09-02-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bbefbc88e69caae5ae8cefbc89/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>[2011.10.08] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-02-08-2011-10-08-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</link><pubDate>Wed, 08 Feb 2012 15:47:54 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-08-2011-10-08-e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>[2011.10.16] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-02-07-2011e5b9b410e69c8816e697a5e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</link><pubDate>Tue, 07 Feb 2012 20:46:01 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-07-2011e5b9b410e69c8816e697a5e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>[2011.10.23] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-02-07-2011e5b9b410e69c8823e697a5e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</link><pubDate>Tue, 07 Feb 2012 18:03:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-07-2011e5b9b410e69c8823e697a5e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</guid><description/></item><item><title>[2011.11.27] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-02-07-2011e5b9b411e69c8827e697a5e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</link><pubDate>Tue, 07 Feb 2012 10:10:06 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-07-2011e5b9b411e69c8827e697a5e5ae9ee9aa8ce5aea4e8aea8e8aebae78fade6b187e680bb/</guid><description>&lt;h1&gt;&lt;/h1&gt;</description></item><item><title>vc2008的signal信号值</title><link>https://blog.perillaroc.wang/post/2012/2012-02-06-vc2008e79a84signale4bfa1e58fb7e580bc/</link><pubDate>Mon, 06 Feb 2012 11:37:07 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-06-vc2008e79a84signale4bfa1e58fb7e580bc/</guid><description/></item><item><title>VC++中的预定义宏</title><link>https://blog.perillaroc.wang/post/2012/2012-02-06-vce4b8ade79a84e9a284e5ae9ae4b989e5ae8f/</link><pubDate>Mon, 06 Feb 2012 11:23:39 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-06-vce4b8ade79a84e9a284e5ae9ae4b989e5ae8f/</guid><description/></item><item><title>VC++中的__declspec关键字</title><link>https://blog.perillaroc.wang/post/2012/2012-02-06-vce4b8ade79a84declspece585b3e994aee5ad97/</link><pubDate>Mon, 06 Feb 2012 10:40:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-06-vce4b8ade79a84declspece585b3e994aee5ad97/</guid><description>&lt;a title="__declspec--MSDN" href="//msdn.microsoft.com/en-us/library/dabb5z75(v=vs.90).aspx" target="_blank"&gt;</description></item><item><title>选择合适的软件版本</title><link>https://blog.perillaroc.wang/post/2012/2012-02-04-e98089e68ba9e59088e98082e79a84e8bdafe4bbb6e78988e69cac/</link><pubDate>Sat, 04 Feb 2012 14:23:14 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-02-04-e98089e68ba9e59088e98082e79a84e8bdafe4bbb6e78988e69cac/</guid><description/></item><item><title>HTML学习小感</title><link>https://blog.perillaroc.wang/post/2012/2012-01-28-htmle5ada6e4b9a0e5b08fe6849f/</link><pubDate>Sat, 28 Jan 2012 20:29:55 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-28-htmle5ada6e4b9a0e5b08fe6849f/</guid><description/></item><item><title>生成不重复随机数的小程序</title><link>https://blog.perillaroc.wang/post/2012/2012-01-16-e7949fe68890e4b88de9878de5a48de99a8fe69cbae695b0e79a84e5b08fe7a88be5ba8f/</link><pubDate>Mon, 16 Jan 2012 20:36:30 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-16-e7949fe68890e4b88de9878de5a48de99a8fe69cbae695b0e79a84e5b08fe7a88be5ba8f/</guid><description/></item><item><title>一个C++小题目</title><link>https://blog.perillaroc.wang/post/2012/2012-01-14-a-cpp-simple-question/</link><pubDate>Sat, 14 Jan 2012 00:15:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-14-a-cpp-simple-question/</guid><description>&lt;p&gt;不用循环和条件控制语句，怎样打印出 1 到 1000 这些数。&lt;/p&gt;
&lt;p&gt;微博上看到有人给出的这个问题的答案，没理解，就自己运行了下。代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;A&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; SUM;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	A(){}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;~&lt;/span&gt;A(){
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		cout &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;501&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;SUM &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34; &amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		SUM&lt;span style="color:#f92672"&gt;--&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; A&lt;span style="color:#f92672"&gt;::&lt;/span&gt;SUM &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_tmain&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; argc, _TCHAR&lt;span style="color:#f92672"&gt;*&lt;/span&gt; argv[])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		vector b(&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		cout &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Done&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	system(&lt;span style="color:#e6db74"&gt;&amp;#34;pause&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从结果看到，确实是从 1 打印到 1000。&lt;/p&gt;
&lt;p&gt;关键在于 &lt;code&gt;main&lt;/code&gt; 函数中 &lt;code&gt;vector&lt;/code&gt; 容器的初始化。
我前几天刚看了 TICPP 也没记住什么，不知道 &lt;code&gt;vector&lt;/code&gt; 如何初始化对象的。
写了一些代码，发现 &lt;code&gt;vector&lt;/code&gt; 调用默认构造函数生成一个临时对象，在用拷贝构造函数将临时对象放入 &lt;code&gt;vector&lt;/code&gt; 中，接着销毁临时对象。
所以才会出现上面的程序中，&lt;code&gt;vector&lt;/code&gt; 有500个对象，但析构函数被调用了 1000 次。&lt;/p&gt;
&lt;p&gt;刚看了 STL 算法这部分的内容，正好可以解决这道题目。
用 &lt;code&gt;generate_n&lt;/code&gt; 结合声称其函数生成 1 到 1000 的 &lt;code&gt;vector&lt;/code&gt; 容器，再用 &lt;code&gt;copy&lt;/code&gt; 算法和 &lt;code&gt;ostream_iterator&lt;/code&gt; 迭代器打印容器内容。
代码如下：&lt;/p&gt;</description></item><item><title>2012，我来了</title><link>https://blog.perillaroc.wang/post/2012/2012-01-12-welcome-2012/</link><pubDate>Thu, 12 Jan 2012 00:32:54 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-12-welcome-2012/</guid><description>&lt;p&gt;转自我的百度空间：&lt;/p&gt;
&lt;p&gt;&amp;lt;//hi.baidu.com/windroc/blog/item/ef43c01b19e243e4ae5133db.html&amp;gt;&lt;/p&gt;
&lt;p&gt;2011年，有些懒惰、有些迷茫、有些幸福、有些快乐，增加许多压力，也倍感时间的重要性。&lt;/p&gt;
&lt;p&gt;因转战到微博，就荒废了这里，没有时间写一些大段的文字，只能做一做复制、粘贴的工作，这严重违背了我自己的想法：即使是拷贝，也要加入自己的内容，更要做好总结并争取提高。
看看这一年的文章，全是转载。
但看看之前的文章，全是没有深度的白水文，就像某人评论的，这类的文章不算是什么有用的文章。&lt;/p&gt;
&lt;p&gt;文章少，除了没有时间外，更重要的原因是没有学习什么东西。
学习了，才有感想，才有经验，才有话说。实践过，才能掌握，才能真正学会一项技术。
这一年来，我学到的东西少之又少，总是做重复的工作。
比如，上半年看到 C++ Primer，没有记住多少内容，年末时看 Thinking in C++，也是没有做练习，没有总结，没有记住多少东西。眼看要回家了，不能把所有书都带回去吧，即使带回去也可能看不完一本。&lt;/p&gt;
&lt;p&gt;时间过得太快，以至于我把握不住自己的命运。
深感自己虚度了之前的五年，没有意识到自己应该做什么，现在却仍然不知道未来的方向在哪里。
面对众多的书籍，不知道拾起哪本来。迷茫的我，自然荒废了这里。
五年来，这里记录了我的些许生活，些许感悟，些许牢骚，些许矛盾，些许期望。
我不想丢弃这里。所以，2012年，我来了。&lt;/p&gt;
&lt;p&gt;忘却之前的遗憾、悔恨、失落、迷茫，抛开一切的负面情绪，昂首挺胸地去做自己应该做的事情。&lt;/p&gt;
&lt;p&gt;我的 2012 年，奋斗、努力、坚定、专注。&lt;/p&gt;</description></item><item><title>用 VS2010 编译Gtest 1.6.0 源码出错</title><link>https://blog.perillaroc.wang/post/2012/2012-01-06-vs2010-build-gtest-has-error/</link><pubDate>Fri, 06 Jan 2012 16:34:35 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-06-vs2010-build-gtest-has-error/</guid><description>&lt;p&gt;编译CMake生成的项目出错。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;gtest-printers_test.cc
D:\Program Files\Microsoft Visual Studio 10.0\VC\include\tuple(127):
 error C2440: “初始化”: 无法从“int”转换为“void *”从整型转换为
 指针类型要求 reinterpret_cast、C 样式转换或函数样式转换
D:\Program Files\Microsoft Visual Studio 10.0\VC\include\tuple(127):
 参见对正在编译的函数 模板 实例化“...省略”的引用
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;问题出在把NULL赋给void*指针。&lt;/p&gt;
&lt;p&gt;gtest-printers_test.cc 代码中这几行出的问题&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;8&amp;#34;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tuple&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;short&lt;/span&gt;, testing&lt;span style="color:#f92672"&gt;::&lt;/span&gt;internal&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Int32, testing&lt;span style="color:#f92672"&gt;::&lt;/span&gt;internal&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Int64, &lt;span style="color:#66d9ef"&gt;float&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;double&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;, string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t10(false, &lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1.5F&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2.5&lt;/span&gt;, str, NULL, &lt;span style="color:#e6db74"&gt;&amp;#34;10&amp;#34;&lt;/span&gt;); 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将最后一行的 &lt;strong&gt;&lt;em&gt;NULL&lt;/em&gt;&lt;/strong&gt; 用 &lt;em&gt;&lt;em&gt;_static_cast&amp;lt;void&lt;/em&gt;&amp;gt;(NULL)_&lt;/em&gt;* 代替就可以编译通过。&lt;/p&gt;
&lt;p&gt;参考：&lt;a href="//groups.google.com/group/googletestframework/browse_thread/thread/dca24032248f77f7/1497bd5aed3a6a95?show_docid=1497bd5aed3a6a95%22"&gt;&amp;ldquo;Google Groups - Re: [googletest] Minor fix for gtest-printers_test&amp;rdquo;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>VC++中目录操作</title><link>https://blog.perillaroc.wang/post/2012/2012-01-05-directory-operation-in-vcpp/</link><pubDate>Thu, 05 Jan 2012 16:54:41 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-05-directory-operation-in-vcpp/</guid><description>&lt;p&gt;在 VC++ 中利用 Windows SDK 操控目录。&lt;/p&gt;
&lt;p&gt;程序中需要用到之前一篇文章中定义的字符串转换函数，具体函数见《&lt;a href="https://blog.perillaroc.wang/post/2012/2012-01-05-wstring-and-string-convert/"&gt;wstring 与 string 的转换&lt;/a&gt;》&lt;/p&gt;
&lt;p&gt;获取当前目录：&lt;code&gt;GetCurrentDirectory()&lt;/code&gt; 函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string getCurrentDirectory( &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; ) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WCHAR Buffer[BUFSIZE];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DWORD dwRet;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dwRet &lt;span style="color:#f92672"&gt;=&lt;/span&gt; GetCurrentDirectory(BUFSIZE, Buffer);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;( dwRet &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;GetCurrentDirectory failed (%d)&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, GetLastError());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(dwRet &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; BUFSIZE) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;Buffer too small; need %d characters&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, dwRet); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;string&lt;/span&gt;(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; wstring &lt;span style="color:#a6e22e"&gt;wstr&lt;/span&gt;(Buffer); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wstring2string&lt;/span&gt;(wstr); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取目录下的文件信息&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FindFirstFile()&lt;/code&gt;、&lt;code&gt;FindNextFile()&lt;/code&gt; 等函数读取文件信息。&lt;/p&gt;
&lt;p&gt;遍历目录下的所有文件和子目录&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FindFirstFile()&lt;/code&gt;、&lt;code&gt;FindNextFile()&lt;/code&gt; 两个函数结合实现。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;listFilesInDirectory&lt;/span&gt;( &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; fileDir, &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; filter, std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;vector&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; fileList ) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WIN32_FIND_DATA ffd; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; HANDLE hFind &lt;span style="color:#f92672"&gt;=&lt;/span&gt; INVALID_HANDLE_VALUE; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; DWORD dwError&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fileList.clear(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; wstring wcdir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; string2wstring(fileDir &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\\&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; filter); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hFind &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FindFirstFile(wcdir.c_str(), &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ffd); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (INVALID_HANDLE_VALUE &lt;span style="color:#f92672"&gt;==&lt;/span&gt; hFind) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _tprintf(TEXT(&lt;span style="color:#e6db74"&gt;&amp;#34;FindFirstFile&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; dwError;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// List all the files in the directory with some info about them. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (ffd.dwFileAttributes &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; FILE_ATTRIBUTE_DIRECTORY) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// dir 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// file 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; string strFileName &lt;span style="color:#f92672"&gt;=&lt;/span&gt; wchar2string(ffd.cFileName); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fileList.push_back(strFileName); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (FindNextFile(hFind, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;ffd) &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dwError &lt;span style="color:#f92672"&gt;=&lt;/span&gt; GetLastError(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (dwError &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; ERROR_NO_MORE_FILES) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _tprintf(TEXT(&lt;span style="color:#e6db74"&gt;&amp;#34;FindFirstFile&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FindClose(hFind); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; dwError; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>wstring与string的转换</title><link>https://blog.perillaroc.wang/post/2012/2012-01-05-wstring-and-string-convert/</link><pubDate>Thu, 05 Jan 2012 16:17:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-05-wstring-and-string-convert/</guid><description>&lt;p&gt;&lt;code&gt;wchar*&lt;/code&gt;、&lt;code&gt;wstring&lt;/code&gt; 和 &lt;code&gt;char*&lt;/code&gt;、&lt;code&gt;std::string&lt;/code&gt; 的相互转换&lt;/p&gt;
&lt;p&gt;字符串是基本内容，必须要掌握。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;string&lt;/code&gt; 实质上是 &lt;code&gt;char&lt;/code&gt; 字符的字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; basic_string&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;, char_traits&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, allocator&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; string; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;wstring&lt;/code&gt; 实质上是 &lt;code&gt;wchar_t&lt;/code&gt; 字符的字符串，即所谓的宽字符。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;typedef&lt;/span&gt; basic_string&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;wchar_t&lt;/span&gt;, char_traits&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;wchar_t&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, allocator&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;wchar_t&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; wstring;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="同类型字符相互转换"&gt;同类型字符相互转换&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;string&lt;/code&gt; 字符串和 &lt;code&gt;char&lt;/code&gt; 字符数组可以直接相互转换。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// char* -&amp;gt; string 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; ch[] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;风中飞舞&amp;#34;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;string &lt;span style="color:#a6e22e"&gt;str1&lt;/span&gt;(ch); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// string -&amp;gt; const char* 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;char&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt; pch &lt;span style="color:#f92672"&gt;=&lt;/span&gt; str1.c_str(); 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果想转换到非常量形式 &lt;code&gt;char*&lt;/code&gt;，可以用 &lt;code&gt;strcpy()&lt;/code&gt; 拷贝到新串，或用 &lt;code&gt;const_cast&amp;lt;&amp;gt;&lt;/code&gt; 运算去掉常量性。
同理，&lt;code&gt;wstring&lt;/code&gt; 和 &lt;code&gt;wchar_t&lt;/code&gt; 数组的转换图上面相同，只不过拷贝串要用 &lt;code&gt;wstrcpy()&lt;/code&gt; 函数。&lt;/p&gt;
&lt;h2 id="不同类型字符相互转换"&gt;不同类型字符相互转换&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;char&lt;/code&gt; 到 &lt;code&gt;wchar_t&lt;/code&gt; 的转换有好几种，标准 C++ 用流函数 &lt;code&gt;os.widen()&lt;/code&gt; 和 &lt;code&gt;os.narrow()&lt;/code&gt; 可以转换单个字符。&lt;/p&gt;
&lt;p&gt;下面用 Windows API 实现 unicode（一般情况下 &lt;code&gt;wchar_t&lt;/code&gt; 使用的编码）和 ansi（&lt;code&gt;char&lt;/code&gt;使用的编码）的相互转换：&lt;/p&gt;</description></item><item><title>C++中生成数字序号形式的字符串</title><link>https://blog.perillaroc.wang/post/2012/2012-01-03-generate-number-strings-in-cpp/</link><pubDate>Tue, 03 Jan 2012 15:05:47 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-03-generate-number-strings-in-cpp/</guid><description>&lt;p&gt;使用 &lt;code&gt;stringstream&lt;/code&gt; 类处理字符串流&lt;/p&gt;
&lt;p&gt;需要读入连续的文件，参考网上用 &lt;code&gt;stringstream &lt;/code&gt;处理字符串的方法，写了下面这个小函数，生成数字序号形式的字符串，用 0 补位。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string getStringIndexFromInt(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; index, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; minLen) 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;stringstream strm; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; strm&lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt;index; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; strm.str(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt;(str.length() &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; minLen){ 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; str; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; str; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用 &lt;code&gt;stringstream&lt;/code&gt; 可以实现任意类型与字符串之间的转换。
下面的程序来自《C++编程思想》第二卷 (C05：StringConv.h)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;sstream&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;typename&lt;/span&gt; T&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; T fromString(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; s) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;istringstream is(s); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; T t; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; is &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; t; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; t; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;typename&lt;/span&gt; T&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;string toString(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; T&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; t) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std&lt;span style="color:#f92672"&gt;::&lt;/span&gt;ostringstream s; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; s &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; t; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; s.str(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面两个模板可以在 string 和任意类型之间实现类型转换。&lt;/p&gt;</description></item><item><title>[2011.12.29] 实验室讨论班汇总</title><link>https://blog.perillaroc.wang/post/2012/2012-01-02-lab-discussion-2011-12-29/</link><pubDate>Mon, 02 Jan 2012 08:21:08 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-02-lab-discussion-2011-12-29/</guid><description>&lt;p&gt;一共六位同学作汇报。下面是我对这次讨论班涉及论文的汇总。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style="font-family: Tahoma;"&gt;&lt;a title="Data-Driven Image Color Theme Enhancement" href="//www.cs.cuhk.hk/~ttwong/papers/colormood/colormood.html"&gt;Data-Driven Image Color Theme Enhancement&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Tahoma;"&gt;&lt;a title="Object Recoloring based on Intrinsic Image Estimation " href="//www.cat.uab.cat/~shida/Research/ObjectRecoloring"&gt;Object Recoloring based on Intrinsic Image Estimation &lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//www.cg.tuwien.ac.at/research/publications/2011/jeschke-2011-est/" title="Estimating Color and Texture Parameters for Vector Graphics"&gt;Estimating Color and Texture Parameters for Vector Graphics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//cns.bu.edu/~lgrady/index.html" title="Leo Grady"&gt;A Seeded Image Segmentation Framework Unifying Graph Cuts And Random Walker Which Yields A New Algorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//www.google.com.hk/#hl=zh-CN&amp;amp;newwindow=1&amp;amp;safe=strict&amp;amp;site=&amp;amp;q=Adaptive+image+and+video+retargeting+technique+based+on+Fourier+analysis&amp;amp;btnK=Google+%E6%90%9C%E7%B4%A2&amp;amp;oq=&amp;amp;aq=&amp;amp;aqi=&amp;amp;aql=&amp;amp;gs_sm=&amp;amp;gs_upl=&amp;amp;bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&amp;amp;fp=a334ebc00792e307&amp;amp;biw=1278&amp;amp;bih=629" title="Adaptive image and video retargeting technique based on Fourier analysis"&gt;Adaptive image and video retargeting technique based on Fourier analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//people.csail.mit.edu/celiu/CVPR2010/index.html" title="Exploring Features in a Bayesian Framework for Material Recognition"&gt;Exploring Features in a Bayesian Framework for Material Recognition&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="1data-driven-image-color-theme-enhancement"&gt;1. &lt;a href="//www.cs.cuhk.hk/~ttwong/papers/colormood/colormood.html" title="Data-Driven Image Color Theme Enhancement"&gt;Data-Driven Image Color Theme Enhancement&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ACM Transactions on Graphics (Special Issue for SIGGRAPH Asia 2010)&lt;/p&gt;</description></item><item><title>一张编程语言历史的图片</title><link>https://blog.perillaroc.wang/post/2012/2012-01-01-a-picture-for-history-of-programming-languages/</link><pubDate>Sun, 01 Jan 2012 20:41:56 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-01-a-picture-for-history-of-programming-languages/</guid><description>&lt;p&gt;按时间线列出编程语言的发展史，并标出语言的来源和演变过程。&lt;/p&gt;
&lt;p&gt;PDF版图片网址：&lt;a href="//www.levenez.com/lang/lang.pdf"&gt;//www.levenez.com/lang/lang.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;新出的几个语言版本：&lt;/p&gt;
&lt;p&gt;C++11标准：&lt;a href="//en.wikipedia.org/wiki/C%2B%2B11"&gt;//en.wikipedia.org/wiki/C%2B%2B11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;C11标准：&lt;a href="//en.wikipedia.org/wiki/C11_(C_standard_revision)"&gt;//en.wikipedia.org/wiki/C11_(C_standard_revision)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Java 7：&lt;a href="//jdk7.java.net/"&gt;//jdk7.java.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Python 3：&lt;a href="//www.python.org/"&gt;//www.python.org/&lt;/a&gt;&lt;/p&gt;</description></item><item><title>OpenCV - 访问Mat矩阵中的元素</title><link>https://blog.perillaroc.wang/post/2012/2012-01-01-opencv-access-elements-in-mat/</link><pubDate>Sun, 01 Jan 2012 20:23:34 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-01-opencv-access-elements-in-mat/</guid><description>&lt;blockquote&gt;
&lt;p&gt;2012.06.07 补记：半年前我对 OpenCV 还不了解，OpenCV 提供多种方法访问 Mat 中的元素，十分方便。这篇文章中提及的几种方法需要重新修改。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mat矩阵中数据指针 &lt;code&gt;Mat.data&lt;/code&gt; 是uchar类型指针，&lt;code&gt;CV_8U&lt;/code&gt; 系列可以通过计算指针位置快速地定位矩阵中的任意元素。&lt;/p&gt;
&lt;p&gt;二维单通道元素可以用 &lt;code&gt;Mat::at(i, j)&lt;/code&gt; 访问，&lt;code&gt;i&lt;/code&gt; 是行序号，&lt;code&gt;j&lt;/code&gt; 是列序号。&lt;/p&gt;
&lt;p&gt;但对于多通道的非 unsigned char 类型矩阵来说，以上方法都不好&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：后来知道可以通过类型转换，用指针访问 data 数据，见后文&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以用 &lt;code&gt;Mat::ptr()&lt;/code&gt; 来获得指向某行元素的指针，在通过行数与通道数计算相应点的指针。&lt;/p&gt;
&lt;p&gt;参照 OpenCV 的 &lt;code&gt;Mat::at()&lt;/code&gt; 函数，写了一个访问二维Mat矩阵的两个简单的小函数，没有边界检查。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;opencv2/core/core.hpp&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;typename&lt;/span&gt; ItemType&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ItemType&lt;span style="color:#f92672"&gt;*&lt;/span&gt; getMatPointPtr(cv&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Mat &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; src, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i , &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; j , &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ItemType&lt;span style="color:#f92672"&gt;*&lt;/span&gt; curRow &lt;span style="color:#f92672"&gt;=&lt;/span&gt; src.ptr&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;itemType&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; curRow &lt;span style="color:#f92672"&gt;+&lt;/span&gt; j &lt;span style="color:#f92672"&gt;*&lt;/span&gt; src.channels() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; c;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;typename&lt;/span&gt; ItemType&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ItemType getMatPoint(cv&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Mat &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; src, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i , &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; j , &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ItemType&lt;span style="color:#f92672"&gt;*&lt;/span&gt; curRow &lt;span style="color:#f92672"&gt;=&lt;/span&gt; src.ptr&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;itemType&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;(curRow &lt;span style="color:#f92672"&gt;+&lt;/span&gt; j &lt;span style="color:#f92672"&gt;*&lt;/span&gt; src.channels() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; c);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;OpenCV 中的 &lt;code&gt;Mat::at()&lt;/code&gt; 代码有严格的边界检测，&lt;code&gt;Mat::ptr()&lt;/code&gt; 也有边界检测，但代码中没有检测 &lt;code&gt;j&lt;/code&gt; 是否越界。&lt;/p&gt;</description></item><item><title>送别2011</title><link>https://blog.perillaroc.wang/post/2012/2012-01-01-farewell2011/</link><pubDate>Sun, 01 Jan 2012 20:12:25 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-01-farewell2011/</guid><description>&lt;p&gt;我挥一挥衣袖，理一理衣襟，慢慢而坚决地跨过2011年，走向崭新的2012年。&lt;/p&gt;
&lt;p&gt;2011年，一路走好。&lt;/p&gt;</description></item><item><title>计算机领域获奖的论文</title><link>https://blog.perillaroc.wang/post/2012/2012-01-01-award-winning-papers-in-cs/</link><pubDate>Sun, 01 Jan 2012 18:58:17 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2012/2012-01-01-award-winning-papers-in-cs/</guid><description>&lt;p&gt;&lt;a href="//jeffhuang.com/" title="Jeff Huang"&gt;Jeff Huang&lt;/a&gt;整理的计算机领域中获奖的论文。&lt;/p&gt;
&lt;p&gt;网址如下：&lt;a href="//jeffhuang.com/best_paper_awards.html" title="best_paper_awards_in_computer_science"&gt;//jeffhuang.com/best_paper_awards.html&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Siggraph 2011 Papers</title><link>https://blog.perillaroc.wang/post/2011/2011-12-30-siggraph-2011-papers/</link><pubDate>Fri, 30 Dec 2011 15:42:21 +0000</pubDate><guid>https://blog.perillaroc.wang/post/2011/2011-12-30-siggraph-2011-papers/</guid><description>&lt;p&gt;仅收录个链接。不想再整理了。&lt;/p&gt;
&lt;p&gt;网址：&lt;a href="https://kesen.realtimerendering.com/sig2011.html"&gt;https://kesen.realtimerendering.com/sig2011.html&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>