ANSA二次开发 - 在ANSA中导入外部Python库

文章目录

在ANSA中导入外部python

NumPy

NumPy是 Python 用于科学计算的扩展。它支持大型多维数组,并具有大量的高级数学函数库来操作这些数组。

从ANSA 21.0.0 开始, v1.18.2版本的NumPy 库被集成到 BETA 中,它使用的是MKL LP64(32位整数)。用户可以通过导入库来访问:

import numpy
numpy.show_config()

有关 NumPy 的更多信息,可点击此链接获取:NumPy

SciPy

Scipy 是Python用于科学计算的一个库(library)。其中包含用于优化、线性代数、集成、插值、FFT、信号处理、ODE 求解等模块。

BETA中安装了1.5.1版本的SciPy。

import scipy
from scipy import linalg
import numpy as np

def find_det():
    arr = np.array([[1, 2],
                    [3, 4]])

    det_res = linalg.det(arr)
    print(det_res)

OpenSSL

OpenSSL 是 TLS 和 SSL 协议的工具包库。它也是一个通用的密码库。

BETA中安装的是1.1.1d版本。

H5py

H5pyHDF5二进制数据格式的python接口。

BETA中安装了2.10.0版本的H5py。

PIP 和venv包和环境管理系统

设置 Python 环境是具有挑战性的,因为库可能有多个依赖关系,并且能在特定的Python版本下工作。而包管理系统可以帮助我们解决这些问题。

PIP

pip 是用于安装和管理 Python 包的标准管理系统。pip随着python一起被发布。BETA Python 接口可以在程序中或从命令行访问它。

命令行访问

BETA_CAE_Systems/shared_v21.0.0/python/python.sh -m pip install requests

在程序中访问

import pip
pip.main(['install','requests'])

venv

venv为在自己的站点目录下创建"虚拟环境"提供支持。每个环境都与自己的 Python 二进制文件及其在站点目录中独立安装的 Python包相隔绝。激活所需的虚拟环境时BETA Python接口(interpeter)将从中导入包(packages ),用户无需对导入的包进行管理。

创建新的虚拟环境:

BETA_CAE_Systems/shared_v21.0.0/python/python.sh -m venv /path/to/create/venv/my_test_venv --system-site-packages

激活新环境:

/path/to/create/venv/my_test_venv/activate

激活将使环境中的Python来激活起来。执行的任何pip安装都将应用于此虚拟环境。ANSA 或 META 可以自动找到此环境的路径。

停用环境:

deactivate

CONDA包和环境管理系统

CONDA 是一个包管理系统,使用它可以轻松安装具有大量依赖性的第三方库。CONDA系统的部分库可以导入到ANSA 和 META中使用 。

以下为使用步骤:

下载Conda

下载并安装Miniconda。Miniconda是Anaconda Python发行版的精简版(reduced version)。

Conda环境安装和设置

需要将Conda安装目录添加到系统的环境路径中。

in bash

export PATH="/home/my_name/miniconda3/bin":{$PATH}

in tcsh

setenv PATH $PATH:/home/my_name/miniconda3/bin

在windows:

c:\miniconda3\scripts

Conda的环境是相互独立的目录结构,其允许相同库的多个版本同时存在。ANSA和META自带Python 3.8。因此,我们需要创建一个兼容Python 3.8的库的环境。

conda create --name python38 python=3.8

最后,需要激活新创建的环境,以便新的安装是针对Python 3.8的。

在Linux系统下:

conda activate python38

注意:
只能在bash中完成虚拟环境的激活工作

在Windows系统下:

conda activate python38

安装库

在激活的环境中安装所需的库采用如下方式:

conda install library_name

将库导入到ANSA和META中

为了将Conda环境导入到ANSA或META脚本中,请在系统路径中添加Conda的Python 3.8的site-packages路径。为了获取site-packages的路径,在Conda的python38环境中运行以下命令:

python3 -c "import site; print(site.getsitepackages()[0])"

在ANSA和META中使用返回的路径来导入所需的库。

import sys

CONDA_ENV = '/home/my_name/miniconda3/envs/python38/lib/python3.8/site-packages'
sys.path.append(CONDA_ENV)

import scipy

公司内联网中的Conda

为了在公司内部网中拥有Python 3.8r的兼容库,在不访问Internet的情况下,需要设置一个Conda Channel。安装了单独的miniconda的用户将能够从本地conda通道(Conda Channel)来安装所需的库。

创建和设置自定义通道的一般指令可以在这里找到。

这里提供了一个python脚本,用于设置conda通道。该脚本在Python 3中运行,需要Internet连接才能下载给定Python版本所需的库。

设置conda通道python脚本:

import sys
import os
import urllib.parse
import urllib.request
import json
import optparse

class CondaRepo():
    def __init__(self, py_version, is_win, is_linux, is_mac):
        self.py_version = py_version
        self.py_version_float = float(py_version)
        if self.py_version_float < 3.5:
            self.main_repos = ['https://repo.anaconda.com/pkgs/free/']
        else:
            self.main_repos = ['https://repo.anaconda.com/pkgs/free/',
                               'https://repo.anaconda.com/pkgs/main/']
        self.output_path = ''
        self.is_win = is_win
        self.is_linux = is_linux
        self.is_mac = is_mac
        self.all_suffixes = ['noarch']

        if self.is_win:
            self.all_suffixes.append('win-64')
        if self.is_linux:
            self.all_suffixes.append('linux-64')
        if self.is_mac:
            self.all_suffixes.append('osx-64')
        
    
    @property
    def output_path(self):
        return self._output_path
    
    @output_path.setter
    def output_path(self, output_path):
        if not output_path:
            self._output_path = output_path
            return 
        
        if not os.path.isdir(output_path):
            raise OSError('channel path is not valid')
        if not os.access(output_path, os.W_OK):
            raise OSError('you do not have permission to write in the channel dir')
        self._output_path = output_path
    
    @property
    def py_version(self):
        return self._py_version
    
    @py_version.setter
    def py_version(self, py_version):
        if not py_version:
            self._py_version = py_version

        versions_dict = {'3.0':'py30',
                         '3.1':'py31',
                         '3.2':'py32',
                         '3.3':'py33',
                         '3.4':'py34',
                         '3.5':'py35',
                         '3.6':'py36',
                         '3.7':'py37',
                         '3.8':'py38'}
        self._py_version = versions_dict[py_version]
    
    @property
    def is_win(self):
        return self._is_win
    
    @is_win.setter
    def is_win(self, is_win):
        if type(is_win) == bool:
            self._is_win = is_win
            return

        bool_dict = {'true':True,
                     'false':False}
        self._is_win = bool_dict[is_win]
    
    @property
    def is_linux(self):
        return self._is_linux
    
    @is_linux.setter
    def is_linux(self, is_linux):
        if type(is_linux) == bool:
            self._is_linux = is_linux
            return

        bool_dict = {'true':True,
                     'false':False}
        self._is_linux = bool_dict[is_linux]
    
    @property
    def is_mac(self):
        return self._is_mac
    
    @is_mac.setter
    def is_mac(self, is_mac):
        if type(is_mac) == bool:
            self._is_mac = is_mac
            return

        bool_dict = {'true':True,
                     'false':False}
        self._is_mac = bool_dict[is_mac]

    def _create_subdir(self, subdir_name):
        dir_path = os.path.join(self.output_path, subdir_name)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

    def _download_libs(self, repos_info, repo, repo_dir):
        subdir = repos_info['info']['subdir']
        subdir_tmp  = os.path.join(repo_dir,subdir)
        self._create_subdir(subdir_tmp)
        save_path = os.path.join(self.output_path, repo_dir, subdir)

        def perform_download(subdir, pack_name):
            pack_name = pack_name.replace('tar.bz2', 'conda')
            save_path_tmp = os.path.join(save_path, pack_name)
            if os.path.exists(save_path_tmp):
                return
            print('downloading : %s - %s ...'%(subdir, pack_name))
            try:
                down_path = os.path.join(repo, subdir, pack_name)
                req = urllib.request.Request(down_path)
                ret = urllib.request.urlopen(req)
            except:
                print('unable to download : %s - %s ...'%(subdir, pack_name))
                pack_name = pack_name.replace('conda', 'tar.bz2')
                save_path_tmp = os.path.join(save_path, pack_name)
                try:
                    print('downloading : %s - %s ...'%(subdir, pack_name))
                    down_path = os.path.join(repo, subdir, pack_name)
                    req = urllib.request.Request(down_path)
                    ret = urllib.request.urlopen(req)
                except:
                    print('unable to download : %s - %s ...'%(subdir, pack_name))
                    return

            with open(save_path_tmp, 'wb') as f:
                f.write(ret.read())
            ret.close()

        perform_download(subdir, 'repodata.json')
        perform_download(subdir, 'repodata.json.bz2')
        #perform_download(subdir, 'repodata_from_packages.json')
        
        for pack_name, pack_info in repos_info['packages'].items():
            if subdir == 'noarch':
                perform_download(subdir, pack_name)
            else:
                if 'py' not in pack_info['build'] or self.py_version in pack_info['build'] or 'py_0' in pack_info['build']:
                    perform_download(subdir, pack_name)

    def _get_repo_info(self, repo, suffix):
        repo_data_path = os.path.join(repo, suffix, 'repodata.json')        
        req = urllib.request.Request(repo_data_path)
        with urllib.request.urlopen(req) as response:
            data = json.load(response)
        return data
    
    def start_download(self):
        workers = []
        for repo in self.main_repos:
            if 'free' in repo:
                subdir = 'free'
            else:
                subdir = 'main'
            self._create_subdir(subdir)
            for suffix in self.all_suffixes:
                repos_info = self._get_repo_info(repo, suffix)
                self._download_libs(repos_info, repo, subdir)

def parse_options():
    parser = optparse.OptionParser()
    parser.add_option('-c','--channel-dir', action='store',
                    default='', dest='channel_dir',
                    help='the setup directory of the conda channel')
    parser.add_option('-w','--windows-download', action='store',
                    default='false', dest='win_down',
                    help='true or false to download windows libraries')
    parser.add_option('-l','--linux-download', action='store',
                    default='false', dest='linux_down',
                    help='true or false to download linux libraries')
    parser.add_option('-m','--mac-download', action='store',
                    default='false', dest='mac_down',
                    help='true or false to download mac libraries')
    parser.add_option('-p','--python-version', action='store',
                    default='3.3', dest='py_version',
                    help='The python version for which to seek libraries 3.x format')
    
    opts, args = parser.parse_args()

    return opts, args

def start():
    opts, args = parse_options()
    bool_str = ('true', 'false')
    py_versions = ('3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8')
    if not opts.channel_dir.strip():
        print('Missing --channel-dir argument. Run --help for details')
        raise SystemExit(1)
    if opts.win_down.lower() not in bool_str:
        print('Incorrect --windows-download argument. Run --help for details')
        raise SystemExit(1)
    if opts.linux_down.lower() not in bool_str:
        print('Incorrect --linux-download argument. Run --help for details')
        raise SystemExit(1)
    if opts.mac_down.lower() not in bool_str:
        print('Incorrect --mac-download argument. Run --help for details')
        raise SystemExit(1)
    if opts.py_version.strip() not in py_versions:
        print('Incorrect --python-version argument. Run --help for details')
        raise SystemExit(1)
    
    cr_obj = CondaRepo(opts.py_version.strip(),
                       opts.win_down.lower(),
                       opts.linux_down.lower(),
                       opts.mac_down.lower())
    cr_obj.output_path = opts.channel_dir.strip()

    cr_obj.start_download()

start()

通道建立后,任何用户都可以访问该通道并安装所需的库。用户需要有一个本地miniconda安装。Conda需要设置为查找创建的通道,而不是在互联网上的远程存储库。要做到这一点,位于用户主目录下的.condarc必须看起来像这样:

channels:
  - http://path/to_my/conda_channel/main/
  - http://path/to_my/conda_channel/free/

此时,用户可以按照上面的说明创建一个python 3.8环境并安装库。

安装Matplotlib

Matplotlib是一个2D绘图库。

为了安装Matplotlib,在前面创建的conda环境中执行:

conda install matplotlib

下面的例子展示了如何在ANSA或META中执行Matplolib代码:

import ansa
import sys

CONDA_ENV = '/home/my_name/miniconda3/envs/python38/lib/python3.8/site-packages'
sys.path.append(CONDA_ENV)


import matplotlib
from matplotlib import pyplot as plt

def my_plot():
    x_vals = [0.2, 0.7, 1.2, 2.7, 3.5]
    y_vals = [1.2, 1.8, 2.4, 3.9, 4.5]

    plt.suptitle('My Graph')
    ax = plt.subplot('111')
    ax.plot(x_vals, y_vals)
    plt.show()

其他库

可以安装和导入其他库到ANSA或META中。例如:Pandas, SymPy等。

注:
在Conda环境中搜索安装新库时,应特别注意确保该库与Python 3.8兼容。


本教程来自为ANSA21帮助文档


扫描下方二维码关注我的微信公众号 - CAE软件二次开发Lab,阅读更多精彩内容!

ANSA二次开发 - 在ANSA中导入外部Python库
CAE软件二次开发Lab

上一篇:如何安装Ruby Gems,并一路将其缓存?


下一篇:ruby – 为什么没有找到sudo:bundle命令?