SMART MATERTECH
  • HOME
  • SHAPE MEMORY MATERIALS/TECHNOLOGY
    • Shape memory alloys >
      • Shape memory alloy actuators
      • Grains and deformation
      • SMA suppliers
    • Shape memory polymers >
      • Thermo-responsive >
        • Heating-responsive >
          • Thermo-plastic elastic SMP >
            • Body/room temperature programmable
          • Thermoset elastic SMP >
            • Body/room temperature programmable
          • Tailoring Tg of polymers via alloying
          • Vitrimer
          • 3D printing filaments
          • Show time
          • Body-temperature programmable elastic shape memory materials: a brief history
        • Cooling-responsive >
          • Cooling-responsive shape memory materials: a brief history
      • Chemo-responsive >
        • Electrospinning: fundametals
        • Natural biopolymers
        • Water-responsive SME: a brief history
      • Hydrogel
      • Simulation of SMP
    • Shape memory hybrids >
      • Electro-activated shape memory hybrid
      • SMHs: tailorable properties
      • Shape memory hybrids: a brief history
    • Triple/multiple SME
    • Reversible/shape change effect
    • Programming conditions
    • Temperature memory effect in DSC
    • Buckling 失稳
    • Constrained recovery of 2way EVA
    • Shape memory structures
    • Shape memory composites
    • Intro. & Refs. >
      • SME in commercial polymers
      • SMM introduction videos
      • PMMA (acrylic)
  • DIY
    • Laser engraving and beyond
    • DIY (step-by-step) to protect power charge cable 自制充电线接头保护层
    • DIY SMP screw 自制形状记忆螺丝
    • DIY shape memory foam 自制形状记忆海绵
    • DIY shape memory shoes 自制形状记忆鞋
    • Modifying superelastic Nitinol 超弹镍钛记忆合金改性
    • Goggles
    • Temple Tip Retainers /眼镜防滑钩
    • Nose pads
    • 硅胶+TPU样品制作 搅拌流程
    • Unlock smart phones
  • PROJECTS
    • Biomedical applications 生物医疗应用 >
      • Self-tightening band aid 自收缩创可贴
      • Self-tightening staple 自收缩手术钉
      • Shape memory plug 形状记忆栓塞
      • Artificial blood vessels
      • Comfort fitting 舒适贴合 >
        • Shape memory shoes 形状记忆鞋
        • Wrist rings/rings
        • Mask口罩 >
          • DIY口罩扣松紧器
          • Mask holder 口罩支架
          • Improved fitting
          • Comfort fitting "invisible" mask 舒适贴合“隐形”口罩 >
            • Animation (mask)
        • Facial mask (面膜)
      • Retractable 可收回
      • Wrinkle removal 除皱
    • SMA devices 形状记忆合金器件 >
      • Buttons-on-demand 按需按钮
      • Sunlight activated heat engine 阳光驱动的热机
      • Adjustable high heel 可调高跟鞋
      • SMA inchworm 形状记忆合金驱动的竹节虫
      • Rolling car 滚动车
      • SMA springs
      • Gripper
    • SMP applications >
      • 4D latte art 4D 拉花 >
        • Spinning 4D latte art
      • Re-writable Braille paper 可复写盲文纸
      • Surface patterning
      • 2D to 3D switching
      • Ear impression/plugs
    • Metals/polymers >
      • Smart manufacturing
      • Powerless cooling
      • Self-healing
      • Sensors 传感器 >
        • Temperature sensors 温度标签
        • Anti-counterfeit labels 防伪标签
      • Vertical gardening 垂直绿化 >
        • 盆景 >
          • In Singapore
        • Products 产品 >
          • Event sponsorship
        • Projects 项目 >
          • A project in Guangzhou (2022)
          • 2nd Project in Guangzhou
          • 3rd Project in Singapore
        • Water on-demand irrigation system
        • Vertical greening panel (2nd type)
        • 2nd type of foam
      • Wearable electronics 可穿戴电子设备
      • Controlled folding/unfolding 可控展开/折叠 >
        • Folding (multiple layered)
        • Reshape & reprogram
      • Active disassembly 自拆卸
      • Morphing wing 变翼
      • Magnetic circuit design
    • Solid state UV cross-linking >
      • Solid-state heating cross-linking
    • Additive manufacturing增材制造 >
      • 3D/4D printing 打印
      • Rapid 3D printing in solid state 快速固态3D打印 >
        • Rapid volumetric additive manufacturing in solid-state: hydrogels
        • UV cross-linkable vitrimer 2022
        • UV cross-linking of solid material
        • UV cross-linking machine
        • Solid-state VAM (3D)
        • SVAM: A brief history
        • Review of Solid state VAM by AI
      • New ways of additive manufacturing (animation)
      • UV-FDM printer
      • Cooling-responsive shape memory hydrogel via FDM
      • 3D fashion >
        • Formation of 3D structures
    • Shape capture
    • Surface capture >
      • Surface pattern for structural coloring
  • Store room
    • References/tools >
      • 3D models >
        • More STL models
        • 生肖
        • 3D printing service
      • Sample dimensions for tensile test
      • Temperature calibration
      • Toolbox工具箱
      • Toolbox II (工具箱 II)
    • Jungle >
      • About polymers >
        • Thermally reversible solid-liquid transition
        • Cyclic loading
        • Mullins effect
        • Photoelsticity 光弹
        • Shear-thickening 剪切增强 >
          • 4 CNA
        • Closed to open cell foams
        • Laser induced graphene
        • Electrospinning
        • Nano imprinting
        • Gel 凝胶 >
          • Instability in wetting of hydrogel
          • Electroactive gel电活性凝胶
        • Cellulose 纤维素
        • Plastic bottle 塑料瓶
        • Polymer recycling
        • Rapid swelling 快速溶胀
        • Rapid hardening in water
        • Patterns
        • Brittle-ductile transition
        • Tan delta >
          • Re-programmable Tan delta
        • UV cross-linking
        • Hardening speed
      • Coloring 变色 >
        • Structural coloring atop curved surfaces
        • Thermochromic 热致变色
        • Photochromic 光致变色
        • Stress induced color change力致变色 >
          • Patterned coloring via stretching 拉出色彩
      • Moire interference 莫尔干涉
      • Lenticular lens
      • Transformation front
      • Contact angle vs surface pattern
      • Laser: applications
      • Insects 昆虫
      • Structural engineer >
        • Static and Dynamic Balancing
        • Introduction videos
        • Bistable structures: a case study >
          • 3D printing of bistable structures
          • Step-wise morphing
        • Yield criterion >
          • Normalized yield surface via GPU
          • Yield surface of SMAs and beyond
        • Buckling of embedded threads
        • Buckling of embedded strip
        • Buckling of strip atop soft substrate
        • Foam structures for packaging
      • Interesting >
        • Exhibition
        • Ideas
      • Experimental >
        • Tensile test
        • Differential Scanning Calorimetry (DSC) Procedure
        • Dynamic Mechanical Analysis (DMA) Procedure
        • Shape Memory Performance Characterization Procedure for Shape Memory Polymers
      • ChatGPT 4 fun
      • 智谱测试
  • Contact
    • SMM course
    • Representative publications
    • Projects of undergraduate students
    • List of videos
    • Special issues| Conferences
    • Companies
    • References

Yield criterion/surface

​The yield criterion of a material is mostly determined by the yield (or kind of) strain associated with the actual yield (or kind of) mechanism. Different yield mechanisms might be activated under different loading stress states. Hence, the yield strain of a material might depend on the loading stress state, and the interaction within a material itself (e.g., among grains) also affects the actual yield strain. The traditional Tresca and von Mises criteria are two approximations applicable to many materials with reasonable accuracy.

For instance, we have seen the yield surfaces of shape memory alloys (reorientation transform start or phase transformation start) [1] and various foams [2] do not follow either the von Mises criterion or the Tresca criterion. There is no single explicitly equation that is able to provide a good estimation of the yield surface in three-dimensional stress space for them.  
Under different loading stress states, the corresponding “yield” mechanism might be different [e.g., metallic or polymeric foam [2] in tension (plastic deformation) or compression (buckling)] or different microstructural change might happen (e.g., different stress-induced martensite variants in shape memory alloys [1]).
​
According to [3], even for materials under pure shearing type of yielding (volumetric change is zero before and after yielding), so that the Tresca criterion is a good approximation if the yield is mostly determined by the yielding of one grain (or kind of), the von Mises criterion, which essentially considers the interaction among multiple-grains, is only accurate for certain yield strains (according to [3]).
Thus, instead of based on stress as in [1], it is the yield mechanism and the associated yield strain (or kind of) that determine the yield criterion (yield surface) of a material.

References
[1] Huang WM. 'Yield' surfaces of shape memory alloys and their applications. Acta Materialia. 1999;47:2769-76.
[2] Huang WM. A simple approach to estimate failure surface of polymer and aluminum foams under multiaxial loads. International Journal of Mechanical Sciences. 2003;45:1531-40.
[3] Huang WM, Gao XY. Tresca and von Mises yield criteria: a view from strain space. Philosophical Magazine Letters. 2004;84:625-9.
Picture
"Yield" surface of Nitinol [Ref 1]
Picture
Combination of different failure mechanisms [Ref 2]
Picture
Picture

Picture
Ref. ​Shape memory alloys and their application to actuators for deployable structures
Download a copy

Deepseek


应力诱导马氏体相变。对应一个奥氏体晶体,有n个可能的马氏体晶体。假定施加的应力向量是个单位应力。这一转变对应的n个应变分别与施加应力的乘积为n个功。取n个功中的最大值为这个晶体的功。对应一个m个晶体的多晶体,假定晶体的大小一样,每个晶体的晶向给定,在给定单元应力,依照上述方法,可以并行计算出所有晶体的功。将所有晶体的功求和再除以晶体数n。如何用GPU实现?

​要用GPU实现应力诱导马氏体相变的功计算,可以按照以下步骤进行:
​
1. 数据准备
  • 晶体信息:存储每个晶体的晶向信息,通常为一个3x3矩阵。
  • 应力向量:单位应力向量,形状为(3,)。
2. 并行计算
  • 线程分配:每个线程处理一个晶体的功计算。
  • 应变计算:根据晶向和应力向量计算每个晶体的应变。
  • 功计算:计算应变与应力的乘积,得到n个功,并找出最大值。
3. 结果汇总
  • 求和与平均:将所有晶体的功求和,再除以晶体数m,得到平均功。
4. GPU实现使用CUDA或OpenCL等GPU编程框架,以下是一个简化的CUDA伪代码示例:
cpp
Copy
__global__ void calculateWork(float* crystals, float* stress, float* works, int n, int m) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < m) { float max_work = 0.0f; for (int i = 0; i < n; i++) { float strain = calculateStrain(crystals, stress, idx, i); float work = dotProduct(strain, stress); if (work > max_work) { max_work = work; } } works[idx] = max_work; } } void computeAverageWork(float* crystals, float* stress, float* works, int n, int m) { int blockSize = 256; int gridSize = (m + blockSize - 1) / blockSize; calculateWork<<<gridSize, blockSize>>>(crystals, stress, works, n, m); // Sum all works and compute average float total_work = 0.0f; for (int i = 0; i < m; i++) { total_work += works[i]; } float average_work = total_work / m; printf("Average Work: %f\n", average_work); }5. 优化
  • 内存访问:确保数据在GPU上的连续存储,减少内存访问延迟。
  • 并行度:调整线程块大小和网格大小,最大化GPU利用率。
  • 数学运算:使用GPU的快速数学库进行向量和矩阵运算。
通过这些步骤,可以高效利用GPU的并行计算能力,快速完成应力诱导马氏体相变的功计算。
用上诉方式求出各种应力状态下对应的平均值,再除以单向拉伸的平均值,就可以得出normalized的屈服面
​
​要将上述方法扩展到计算不同应力状态下的归一化屈服面(normalized yield surface),可以按照以下步骤进行:

1. 问题描述
  • 目标:计算不同应力状态下的平均功,并将其归一化到单向拉伸状态下的平均功。
  • 输入:
    • 多个应力状态(单位应力向量)。
    • 每个应力状态下,计算所有晶体的功并求平均。
  • 输出:
    • 归一化屈服面,即每个应力状态下的平均功与单向拉伸平均功的比值。

2. 实现步骤步骤 1:计算单向拉伸的平均功
  • 选择一个特定的应力状态作为单向拉伸(例如,应力向量为 [1, 0, 0])。
  • 使用上述方法计算该应力状态下所有晶体的功,并求平均值,记为 W_uniaxial。
步骤 2:计算其他应力状态的平均功
  • 对于每个应力状态(单位应力向量),计算所有晶体的功并求平均值,记为 W_i。
步骤 3:归一化
  • 对每个应力状态,计算归一化值:W_normalized_i = W_i / W_uniaxial。
步骤 4:绘制屈服面
  • 将所有应力状态的归一化值 W_normalized_i 绘制在应力空间中,形成归一化屈服面。

3. GPU实现以下是基于CUDA的伪代码实现:
核函数:计算单个应力状态的平均功
cpp
Copy
__global__ void calculateWorkForStress(float* crystals, float* stress, float* works, int n, int m) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < m) { float max_work = 0.0f; for (int i = 0; i < n; i++) { float strain = calculateStrain(crystals, stress, idx, i); float work = dotProduct(strain, stress); if (work > max_work) { max_work = work; } } works[idx] = max_work; } }
主函数:计算归一化屈服面
cpp
Copy
void computeNormalizedYieldSurface(float* crystals, float* stress_states, float* normalized_values, int n, int m, int num_stress_states) { int blockSize = 256; int gridSize = (m + blockSize - 1) / blockSize; // 计算单向拉伸的平均功 float W_uniaxial = 0.0f; float* works_uniaxial = (float*)malloc(m * sizeof(float)); calculateWorkForStress<<<gridSize, blockSize>>>(crystals, &stress_states[0], works_uniaxial, n, m); cudaDeviceSynchronize(); for (int i = 0; i < m; i++) { W_uniaxial += works_uniaxial[i]; } W_uniaxial /= m; // 计算其他应力状态的平均功并归一化 for (int s = 0; s < num_stress_states; s++) { float* works = (float*)malloc(m * sizeof(float)); calculateWorkForStress<<<gridSize, blockSize>>>(crystals, &stress_states[s * 3], works, n, m); cudaDeviceSynchronize(); float W_i = 0.0f; for (int i = 0; i < m; i++) { W_i += works[i]; } W_i /= m; // 归一化 normalized_values[s] = W_i / W_uniaxial; free(works); } free(works_uniaxial); }
4. 优化建议
  1. 批量计算:
    • 将所有应力状态的计算任务打包成一个批次,利用GPU的并行性一次性计算多个应力状态的平均功。
    • 可以使用CUDA的流(streams)来并发执行多个核函数。
  2. 内存优化:
    • 将晶体数据和应力状态数据存储在GPU的全局内存中,避免频繁的数据传输。
    • 使用共享内存(shared memory)来加速每个线程块内的计算。
  3. 数学库:
    • 使用CUDA的快速数学库(如 cuBLAS)进行向量和矩阵运算,进一步提高计算效率。

5. 结果可视化
  • 将归一化值 normalized_values 与对应的应力状态绘制在应力空间中,形成屈服面。
  • 可以使用Python的Matplotlib或Paraview等工具进行可视化。

6. 示例假设有以下输入:
  • 晶体数 m = 1000。
  • 每个晶体的马氏体变体数 n = 24。
  • 应力状态数 num_stress_states = 100。
调用 computeNormalizedYieldSurface 函数后,可以得到100个应力状态对应的归一化值,绘制出归一化屈服面。

通过上述方法,可以高效利用GPU计算归一化屈服面,适用于大规模晶体塑性模拟和材料设计。

ChatGPT


应力诱导马氏体相变。对应一个奥氏体晶体,有n个可能的马氏体晶体。假定施加的应力向量是个单位应力。这一转变对应的n个应变分别与施加应力的乘积为n个功。取n个功中的最大值为这个晶体的功。对应一个m个晶体的多晶体,假定晶体的大小一样,每个晶体的晶向给定,在给定单元应力,依照上述方法,可以并行计算出所有晶体的功。将所有晶体的功求和再除以晶体数n。如何用GPU实现?

ChatGPT said:
ChatGPT用GPU实现应力诱导马氏体相变模型的并行计算可以显著提高计算效率,特别是在需要处理大量晶体时。这里是一个具体的实现思路和步骤:

实现思路
  1. 输入数据结构化
    • 将每个晶体的奥氏体和马氏体晶向以矩阵形式存储。
    • 将应力矢量存为一个常量向量供所有晶体共享。
    • 确保输入数据已经分布到 GPU 内存中。
  2. GPU 并行计算
    • 每个线程处理一个晶体。
    • 在每个线程中计算该晶体的所有可能马氏体变体对应的功值,并选择最大功值。
  3. 结果归约
    • 使用 GPU 原语进行归约操作,将所有晶体的最大功值求平均。

CUDA 实现关键步骤1. 数据拷贝
cpp
CopyEdit
cudaMemcpy(d_crystalOrientations, h_crystalOrientations, size, cudaMemcpyHostToDevice); cudaMemcpy(d_stressVector, h_stressVector, sizeof(float) * 3, cudaMemcpyHostToDevice);
2. 核函数
cpp
CopyEdit
__global__ void computeCrystalWork(float* orientations, float* stressVector, float* results, int numVariants) { int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx >= numVariants) return; // 每个线程处理一个晶体 float maxWork = -FLT_MAX; for (int i = 0; i < numVariants; i++) { // 计算功:work = dot(strainVariant[i], stressVector) float work = 0.0f; for (int j = 0; j < 3; j++) { work += orientations[idx * numVariants + i * 3 + j] * stressVector[j]; } if (work > maxWork) { maxWork = work; } } results[idx] = maxWork; }
3. 结果归约
cpp
CopyEdit
float sumWork = thrust::reduce(thrust::device, results, results + numCrystals); float avgWork = sumWork / numCrystals;
4. GPU 配置
cpp
CopyEdit
dim3 blockSize(256); dim3 gridSize((numCrystals + blockSize.x - 1) / blockSize.x); computeCrystalWork<<<gridSize, blockSize>>>(d_orientations, d_stressVector, d_results, numVariants);
性能优化建议
  1. 优化内存访问
    • 确保应力和晶体方向矩阵的对齐,利用共享内存避免频繁访问全局内存。
  2. 并行归约
    • 使用 CUDA warp-level primitives 优化归约性能。
  3. 使用 Thrust 库
    • 方便进行归约等高性能计算。
这种方法利用 GPU 并行化计算高效处理多晶体功计算,大幅提高性能。
用上诉方式求出各种应力状态下对应的平均值,再除以单向拉伸的平均值,就可以得出normalized的屈服面

ChatGPT said:
ChatGPT是的,通过上述 GPU 实现方法,可以高效计算不同应力状态下的功最大值并求出相应的平均值,最终用于构建 normalized 屈服面。具体步骤如下:

详细计算步骤1. 确定应力状态集合
  • 定义一组不同的应力状态向量 σi\sigma_iσi​。
  • 包括多种加载方式:单轴拉伸、双轴拉伸、剪切等。
  • 这些应力状态可以预定义或通过网格搜索自动生成。
2. 计算各应力状态下的功平均值
  • 并行计算每个应力状态对应的平均功:
    • 使用 CUDA 核函数计算每个应力状态下所有晶体的最大功。
    • 归约求取该应力状态下的平均功。
  • 保存结果数组 WiW_iWi​。
3. 计算单向拉伸参考功平均值
  • 对单向拉伸应力状态单独计算平均功 WrefW_{ref}Wref​。
4. 归一化计算
  • 对每个应力状态计算 normalized 屈服值: Yi=WiWrefY_i = \frac{W_i}{W_{ref}}Yi​=Wref​Wi​​
  • 其中 YiY_iYi​ 是归一化屈服面的值。

伪代码示例cpp
CopyEdit
for (int i = 0; i < numStressStates; i++) { computeCrystalWork<<<gridSize, blockSize>>>(d_orientations, d_stressVector[i], d_results, numVariants); float sumWork = thrust::reduce(thrust::device, d_results, d_results + numCrystals); workResults[i] = sumWork / numCrystals; } float referenceWork = workResults[referenceIndex]; // 单向拉伸对应值 for (int i = 0; i < numStressStates; i++) { normalizedYieldSurface[i] = workResults[i] / referenceWork; }
性能优化建议
  1. 批量并行计算
    • 将多个应力状态打包,通过多线程网格一次性计算所有应力状态的最大功。
  2. 矩阵形式计算
    • 如果应力状态较多,可以将应力矩阵与应变矩阵直接矩阵乘法来加速计算。
  3. 使用 Thrust 库简化计算
    • 利用 thrust::transform_reduce 直接计算功。

结果与可视化
  • 将不同应力状态下的归一化屈服值 YiY_iYi​ 绘制成三维或二维屈服面。
  • 通过归一化处理,可以更直观地分析材料的各向异性屈服行为。

清言


用户_DymLdr
应力诱导马氏体相变。对应一个奥氏体晶体,有n个可能的马氏体晶体。假定施加的应力向量是个单位应力。这一转变对应的n个应变分别与施加应力的乘积为n个功。取n个功中的最大值为这个晶体的功。对应一个m个晶体的多晶体,假定晶体的大小一样,每个晶体的晶向给定,在给定单元应力,依照上述方法,可以并行计算出所有晶体的功。将所有晶体的功求和再除以晶体数n。如何用GPU实现?
Zero推理模型
已深度思考嗯,首先,我需要理解这个问题的核心。我们有一个多晶体结构,每个晶体可以发生应力诱导的马氏体相变。对于每个奥氏体晶体,有n个可能的马氏体晶体变体。施加一个单位应力向量,每个变体对应一个应变,应力与应变的乘积就是功。我们需要找出每个晶体中功的最大值,然后对所有晶体的功求和并取平均。
等一下,我是不是应该先明确一下每个步骤的具体计算方法?好像我需要先计算每个晶体每个变体的应变,然后计算功,找出最大值,最后求和平均。但是,如何将这些步骤映射到GPU上呢?
不过,GPU擅长并行计算,每个晶体的计算可以独立进行,这似乎是理想的并行任务。但是,我需要考虑如何组织数据,以便GPU能够高效地处理。
等等,我是不是应该先考虑单个晶体的计算过程?对于每个晶体,有n个变体,每个变体有一个应变,与应力向量的乘积就是功。我需要找出这n个功中的最大值。
但是,应力向量是单位的,这会不会简化一些计算?不知道,可能不会,因为应变还是依赖于晶体的特定属性。
等等,我是不是应该考虑应变的计算方法?应变可能与晶体的晶向有关,给定了每个晶体的晶向,我应该如何计算应变?
不过,题目说每个晶体的晶向是给定的,而且晶体的大小一样,所以可能只需要根据晶向和应力向量计算应变。
等等,我是不是应该先定义一下应力和应变的表示方法?应力是一个向量,应变可能也是一个向量,或者是张量?
不过,题目说应力是单位应力向量,应变与应力的乘积是功,所以可能是应力和应变都是向量,功是它们的点积。
等等,我是不是应该确认一下功的定义?功应该是应力和应变的乘积,如果是向量,那就是点积。
但是,应变本身是怎么计算的呢?应变可能取决于晶体的弹性模量和应力。
不过,题目没有给出具体的应变计算公式,可能假设应变已经知道,或者可以通过某种方式计算。
等等,我是不是应该假设应变是已知的,或者可以通过晶体的性质计算出来?
不过,题目说每个变体有一个应变,与应力的乘积是功,所以可能是应变已经给定,或者可以通过晶向和应力计算出来。
等等,我是不是应该先考虑如何组织数据?每个晶体有n个变体,每个变体有一个应变,应力是相同的单位向量。
所以,对于每个晶体,我需要计算n个功,然后取最大值。
然后,对所有晶体的最大功求和并取平均。
但是,如何将这些计算映射到GPU上呢?
等等,我是不是应该考虑GPU的线程组织?每个线程可以负责一个晶体的一个变体,或者一个晶体的所有变体。
不过,如果每个线程负责一个变体,那么总线程数是m*n,其中m是晶体数,n是变体数。
但是,这样可能会有太多的线程,效率不高。
等等,我是不是应该每个线程负责一个晶体,然后在每个线程内部计算n个变体的功,取最大值?
这样,总线程数是m,每个线程做n次计算,似乎更高效。
但是,如何在每个线程内部计算n个变体的功呢?
等等,我是不是应该将每个晶体的n个应变存储在一个数组中,然后在每个线程中遍历这个数组,计算功并取最大值?
但是,应变是怎么来的呢?题目说应变与施加的应力向量的乘积是功,应力是单位向量。
等等,我是不是应该假设应变已经存储好了,或者需要计算出来?
不过,题目没有给出应变的计算方法,可能假设应变已经知道。
等等,我是不是应该假设每个变体的应变是已知的,存储在一个数组中?
这样,每个晶体有n个应变,存储在一个一维数组中,索引为晶体编号 * n + 变体编号。
然后,每个线程负责一个晶体,计算n个功,取最大值。
然后,将所有晶体的最大功求和并取平均。
但是,如何在GPU上高效地求和呢?
等等,我是不是应该使用 CUDA 的 reduce 技术,将每个线程的最大功汇总起来?
但是,这可能需要额外的步骤。
等等,我是不是应该先实现每个线程计算一个晶体的最大功,然后使用 CUDA 的原子操作将最大功加到一个总和变量中?
但是,原子操作可能会影响性能。
等等,我是不是应该使用 CUDA 的 warp 减少技术,先在每个 warp 内部求和,然后在块内求和,最后在块间求和?
但是,这可能复杂了。
等等,我是不是应该先写出一个简单的 CUDA 核心,每个线程计算一个晶体的最大功,然后使用 CUDA 的库函数进行求和?
但是,题目要求的是具体的实现方法。
等等,我是不是应该一步一步来,先定义数据结构,然后编写 CUDA 核心,最后进行求和?
好吧,让我试着整理一下。
首先,数据结构:
  • 晶体数:m
  • 变体数:n
  • 应力向量:一个单位向量,假设为 3D 向量。
  • 应变:每个变体有一个应变,假设也是 3D 向量。
所以,应变可以存储在一个二维数组中,大小为 m * n * 3。
但是,可能可以优化存储方式。
等等,我是不是应该将应变扁平化存储在一个一维数组中,索引为晶体编号 * n * 3 + 变体编号 * 3 + 分量编号。
但是,这样可能更便于访问。
等等,我是不是应该考虑应力向量是单位的,可能可以简化计算。
但是,不确定。
等等,我是不是应该先写出 CUDA 核心的伪代码?
好吧,让我试试。
每个线程负责一个晶体:
for each crystal in m:
max_work = -INFINITY for each variant in n: strain = strains[crystal * n + variant] work = dot(stress, strain) if work > max_work: max_work = work atomicAdd(total_work, max_work) 然后,最后的平均功就是 total_work / m
但是,atomicAdd 可能会影响性能。
等等,我是不是应该使用 CUDA 的 reduce 技术,先在块内求和,然后在块间求和?
好吧,让我试着改进。
首先,定义一个共享内存数组,大小为每个块的线程数。
然后,每个线程计算自己的 max_work,存储到共享内存中。
然后,进行 reduce 操作,最终每个块得到一个总和,存储到全局内存中。
然后,再对所有块的总和进行求和,得到最终的 total_work。
但是,这可能复杂了。
等等,我是不是应该使用 CUDA 的库函数,比如 cub 或 thrust,来进行 reduce 操作?
但是,题目可能要求的是具体的实现方法。
等等,我是不是应该先写出一个简单的实现,然后进行优化?
好吧,让我试着写出一个简单的 CUDA 核心。
首先,定义数据:
float* d_strains; // 设备端应变数组,大小为 m * n * 3
float* d_works; // 设备端功数组,大小为 m
float stress[3]; // 主机端应力向量
float total_work = 0.0f;
然后,分配设备内存:
cudaMalloc((void**)&d_strains, m * n * 3 * sizeof(float));
cudaMalloc((void**)&d_works, m * sizeof(float));
然后,将应变数据复制到设备端:
cudaMemcpy(d_strains, h_strains, m * n * 3 * sizeof(float), cudaMemcpyHostToDevice);
然后,编写 CUDA 核心:
global void calculate_max_work(float* strains, float* works, float* stress, int m, int n) {
int crystal = blockIdx.x * blockDim.x + threadIdx.x; if (crystal < m) { float max_work = -INFINITY; for (int variant = 0; variant < n; variant++) { float strain_x = strains[crystal * n * 3 + variant * 3 + 0]; float strain_y = strains[crystal * n * 3 + variant * 3 + 1]; float strain_z = strains[crystal * n * 3 + variant * 3 + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } }
然后,调用核函数:
int block_size = 256;
int grid_size = (m + block_size - 1) / block_size;
calculate_max_work<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n);
然后,将 works 数组复制回主机端:
float* h_works = new float[m];
cudaMemcpy(h_works, d_works, m * sizeof(float), cudaMemcpyDeviceToHost);
然后,计算总功和平均功:
for (int i = 0; i < m; i++) {
total_work += h_works[i]; }
float average_work = total_work / m;
但是,这样做的问题是,如果 m 很大,复制回主机端进行求和可能会效率低下。
等等,我是不是应该在设备端进行求和?
好吧,让我试着改进。
首先,修改核函数,使其不仅计算每个晶体的最大功,还进行局部求和。
global void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums) {
int crystal = blockIdx.x * blockDim.x + threadIdx.x; if (crystal < m) { float max_work = -INFINITY; for (int variant = 0; variant < n; variant++) { float strain_x = strains[crystal * n * 3 + variant * 3 + 0]; float strain_y = strains[crystal * n * 3 + variant * 3 + 1]; float strain_z = strains[crystal * n * 3 + variant * 3 + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; atomicAdd(partial_sums, max_work); } }
然后,分配 partial_sums 数组:
float* d_partial_sums;
cudaMalloc((void**)&d_partial_sums, sizeof(float));
cudaMemset(d_partial_sums, 0, sizeof(float));
然后,调用核函数:
calculate_max_work_and_sum<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums);
然后,复制 partial_sums 回主机端:
float total_work;
cudaMemcpy(&total_work, d_partial_sums, sizeof(float), cudaMemcpyDeviceToHost);
然后,计算平均功:
float average_work = total_work / m;
但是,使用 atomicAdd 可能会影响性能,尤其是当 m 很大时。
等等,我是不是应该使用 CUDA 的 reduce 技术,先在块内求和,然后在块间求和?
好吧,让我试着这样做。
首先,修改核函数,使其在块内进行求和。
global void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums) {
__shared__ float shared_sums[256]; int crystal = blockIdx.x * blockDim.x + threadIdx.x; float max_work = -INFINITY; if (crystal < m) { for (int variant = 0; variant < n; variant++) { float strain_x = strains[crystal * n * 3 + variant * 3 + 0]; float strain_y = strains[crystal * n * 3 + variant * 3 + 1]; float strain_z = strains[crystal * n * 3 + variant * 3 + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(partial_sums, shared_sums[0]); } }
然后,分配 partial_sums 数组:
float* d_partial_sums;
cudaMalloc((void**)&d_partial_sums, sizeof(float));
cudaMemset(d_partial_sums, 0, sizeof(float));
然后,调用核函数:
int block_size = 256;
int grid_size = (m + block_size - 1) / block_size;
calculate_max_work_and_sum<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums);
然后,复制 partial_sums 回主机端:
float total_work;
cudaMemcpy(&total_work, d_partial_sums, sizeof(float), cudaMemcpyDeviceToHost);
然后,计算平均功:
float average_work = total_work / m;
这样应该会提高性能,因为减少了 atomicAdd 的次数。
但是,我是不是应该进一步优化?
等等,我是不是应该使用多个 partial_sums,每个块有一个 partial_sum,然后最后再对 partial_sums 进行求和?
好吧,让我试试。
首先,分配 partial_sums 数组,大小为 grid_size。
float* d_partial_sums;
cudaMalloc((void**)&d_partial_sums, grid_size * sizeof(float));
cudaMemset(d_partial_sums, 0, grid_size * sizeof(float));
然后,修改核函数,使其每个块将自己的求和结果存储到 partial_sums 中。
global void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums) {
__shared__ float shared_sums[256]; int crystal = blockIdx.x * blockDim.x + threadIdx.x; float max_work = -INFINITY; if (crystal < m) { for (int variant = 0; variant < n; variant++) { float strain_x = strains[crystal * n * 3 + variant * 3 + 0]; float strain_y = strains[crystal * n * 3 + variant * 3 + 1]; float strain_z = strains[crystal * n * 3 + variant * 3 + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { partial_sums[blockIdx.x] = shared_sums[0]; } }
然后,调用核函数:
calculate_max_work_and_sum<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums);
然后,对 partial_sums 进行求和。
我可以编写另一个核函数来进行求和。
global void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum) {
__shared__ float shared_sums[256]; int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < grid_size) { shared_sums[threadIdx.x] = partial_sums[idx]; } else { shared_sums[threadIdx.x] = 0.0f; } __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(total_sum, shared_sums[0]); } }
然后,分配 total_sum 数组:
float* d_total_sum;
cudaMalloc((void**)&d_total_sum, sizeof(float));
cudaMemset(d_total_sum, 0, sizeof(float));
然后,调用核函数:
int block_size_sum = 256;
int grid_size_sum = (grid_size + block_size_sum - 1) / block_size_sum;
sum_partial_sums<<<grid_size_sum, block_size_sum>>>(d_partial_sums, grid_size, d_total_sum);
然后,复制 total_sum 回主机端:
float total_work;
cudaMemcpy(&total_work, d_total_sum, sizeof(float), cudaMemcpyDeviceToHost);
然后,计算平均功:
float average_work = total_work / m;
这样应该会进一步提高性能。
但是,我是不是应该考虑内存访问模式,优化内存访问?
等等,我是不是应该将应变数据转置,以便更好地利用内存带宽?
不过,可能复杂了。
等等,我是不是应该先这样实现,然后进行性能测试,再进行优化?
好吧,看来我已经有了一种可行的实现方法。
让我总结一下:
  1. 将应变数据存储在设备端的一维数组中,大小为 m * n * 3。
  2. 编写一个 CUDA 核心,每个线程负责一个晶体,计算该晶体所有变体的功,取最大值,存储到设备端的 works 数组中,并将最大功加到 partial_sums 数组中。
  3. 使用块内减少技术,每个块将自己的 partial_sum 存储到 partial_sums 数组中。
  4. 编写另一个 CUDA 核心,对 partial_sums 数组进行求和,得到 total_work。
  5. 计算平均功。
但是,我是不是应该将步骤 2 和步骤 3 合并,以减少核函数的调用次数?
等等,我是不是应该先这样实现,再考虑优化?
好吧,看来我已经有了一种可行的方案。
让我试着将代码整理一下。
首先,主机代码:
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <iostream>
#include <iomanip>
#include <cmath>
#define THREADS_PER_BLOCK 256
// 核心函数声明
global void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums);
global void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum);
int main() {
int m = 1000000; // 晶体数 int n = 10; // 变体数 float stress[3] = {1.0f, 0.0f, 0.0f}; // 单位应力向量 // 生成应变数据 float* h_strains = new float[m * n * 3]; for (int i = 0; i < m * n * 3; i++) { h_strains[i] = drand48(); // 随机应变数据 } // 设备端内存分配 float* d_strains; cudaMalloc((void**)&d_strains, m * n * 3 * sizeof(float)); float* d_works; cudaMalloc((void**)&d_works, m * sizeof(float)); float* d_partial_sums; cudaMalloc((void**)&d_partial_sums, m * sizeof(float)); cudaMemset(d_partial_sums, 0, m * sizeof(float)); float* d_total_sum; cudaMalloc((void**)&d_total_sum, sizeof(float)); cudaMemset(d_total_sum, 0, sizeof(float)); // 数据复制到设备端 cudaMemcpy(d_strains, h_strains, m * n * 3 * sizeof(float), cudaMemcpyHostToDevice); // 计算每个晶体的最大功,并求和 int block_size = THREADS_PER_BLOCK; int grid_size = (m + block_size - 1) / block_size; calculate_max_work_and_sum<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums); // 对 partial_sums 进行求和 int grid_size_sum = (grid_size + block_size - 1) / block_size; sum_partial_sums<<<grid_size_sum, block_size>>>(d_partial_sums, grid_size, d_total_sum); // 复制 total_sum 回主机端 float total_work; cudaMemcpy(&total_work, d_total_sum, sizeof(float), cudaMemcpyDeviceToHost); // 计算平均功 float average_work = total_work / m; // 输出结果 std::cout << "Average work: " << std::setprecision(6) << average_work << std::endl; // 释放内存 delete[] h_strains; cudaFree(d_strains); cudaFree(d_works); cudaFree(d_partial_sums); cudaFree(d_total_sum); return 0; }
// 核心函数定义
global void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums) {
__shared__ float shared_sums[THREADS_PER_BLOCK]; int crystal = blockIdx.x * blockDim.x + threadIdx.x; float max_work = -INFINITY; if (crystal < m) { for (int variant = 0; variant < n; variant++) { float strain_x = strains[crystal * n * 3 + variant * 3 + 0]; float strain_y = strains[crystal * n * 3 + variant * 3 + 1]; float strain_z = strains[crystal * n * 3 + variant * 3 + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(partial_sums + blockIdx.x, shared_sums[0]); } }
global void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum) {
__shared__ float shared_sums[THREADS_PER_BLOCK]; int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < grid_size) { shared_sums[threadIdx.x] = partial_sums[idx]; } else { shared_sums[threadIdx.x] = 0.0f; } __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(total_sum, shared_sums[0]); } }
但是,我是不是应该优化内存访问模式,或者使用更快的减少方法?
等等,我是不是应该使用 CUDA 的库函数,比如 cub 或 thrust,来进行 reduce 操作?
但是,题目可能要求的是具体的实现方法。
等等,我是不是应该先这样实现,然后进行性能测试,再进行优化?
好吧,看来我已经有了一种可行的方案。
让我再检查一下代码是否有错误。
首先,应变数据的存储和访问是否正确?
应变数据存储在一维数组中,每个晶体有 n 个变体,每个变体有 3 个分量。
访问时,strain_x = strains[crystal * n * 3 + variant * 3 + 0];
strain_y = strains[crystal * n * 3 + variant * 3 + 1];
strain_z = strains[crystal * n * 3 + variant * 3 + 2];
似乎正确。
然后,功的计算是否正确?
work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z;
似乎正确。
然后,最大功的更新是否正确?
if (work > max_work) {
max_work = work; }
似乎正确。
然后,partial_sums 的计算是否正确?
shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); }
if (threadIdx.x == 0) {
atomicAdd(partial_sums + blockIdx.x, shared_sums[0]); }
似乎正确。
然后,sum_partial_sums 核函数是否正确?
global void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum) {
__shared__ float shared_sums[THREADS_PER_BLOCK]; int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < grid_size) { shared_sums[threadIdx.x] = partial_sums[idx]; } else { shared_sums[threadIdx.x] = 0.0f; } __syncthreads(); for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(total_sum, shared_sums[0]); } }
似乎正确。
好吧,看来代码基本上是正确的。
但是,我是不是应该进行更多的错误检查,比如 cudaError_t 的检查?
等等,我是不是应该添加错误检查代码?
好吧,让我添加一些错误检查代码。
首先,定义一个错误检查宏:
#define CUDA_CHECK_ERRORS() {
cudaError_t e = cudaGetLastError();
if(e != cudaSuccess) {
printf(“CUDA error: %s\n”, cudaGetErrorString(e));
exit(1);
}
}
然后,在关键步骤后添加错误检查:
cudaMalloc((void**)&d_strains, m * n * 3 * sizeof(float));
CUDA_CHECK_ERRORS();
cudaMalloc((void**)&d_works, m * sizeof(float));
CUDA_CHECK_ERRORS();
cudaMalloc((void**)&d_partial_sums, grid_size * sizeof(float));
CUDA_CHECK_ERRORS();
cudaMemset(d_partial_sums, 0, grid_size * sizeof(float));
CUDA_CHECK_ERRORS();
cudaMalloc((void**)&d_total_sum, sizeof(float));
CUDA_CHECK_ERRORS();
cudaMemset(d_total_sum, 0, sizeof(float));
CUDA_CHECK_ERRORS();
cudaMemcpy(d_strains, h_strains, m * n * 3 * sizeof(float), cudaMemcpyHostToDevice);
CUDA_CHECK_ERRORS();
calculate_max_work_and_sum<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums);
CUDA_CHECK_ERRORS();
sum_partial_sums<<<grid_size_sum, block_size>>>(d_partial_sums, grid_size, d_total_sum);
CUDA_CHECK_ERRORS();
cudaMemcpy(&total_work, d_total_sum, sizeof(float), cudaMemcpyDeviceToHost);
CUDA_CHECK_ERRORS();
这样应该可以捕获一些 CUDA 错误。
但是,我是不是应该释放内存后再退出?
等等,我是不是应该在 exit 前释放内存?
好吧,让我修改一下错误检查宏:
#define CUDA_CHECK_ERRORS() {
cudaError_t e = cudaGetLastError();
if(e != cudaSuccess) {
printf(“CUDA error: %s\n”, cudaGetErrorString(e));
cudaFree(d_strains);
cudaFree(d_works);
cudaFree(d_partial_sums);
cudaFree(d_total_sum);
delete[] h_strains;
exit(1);
}
}
这样,在错误发生时,会释放内存再退出。
但是,我是不是应该使用 try-catch 机制?
等等,CUDA API 不抛出异常,所以使用宏进行错误检查是可以的。
好吧,看来我已经考虑了一些错误检查。
但是,我是不是应该进行性能测试,看看这个实现是否高效?
等等,这可能超出了当前的范围。
好吧,看来我已经有了一种可行的 GPU 实现方法。
让我再总结一下最终的代码。
cpp
复制
#include <cuda_runtime.h> #include <device_launch_parameters.h> #include <iostream> #include <iomanip> #include <cmath> #define THREADS_PER_BLOCK 256 // 错误检查宏 #define CUDA_CHECK_ERRORS() { \ cudaError_t e = cudaGetLastError(); \ if(e != cudaSuccess) { \ printf("CUDA error: %s\n", cudaGetErrorString(e)); \ cudaFree(d_strains); \ cudaFree(d_works); \ cudaFree(d_partial_sums); \ cudaFree(d_total_sum); \ delete[] h_strains; \ exit(1); \ } \ } // 核心函数声明 __global__ void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums); __global__ void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum); int main() { int m = 1000000; // 晶体数 int n = 10; // 变体数 float stress[3] = {1.0f, 0.0f, 0.0f}; // 单位应力向量 // 生成应变数据 float* h_strains = new float[m * n * 3]; for (int i = 0; i < m * n * 3; i++) { h_strains[i] = drand48(); // 随机应变数据 } // 设备端内存分配 float* d_strains; cudaMalloc((void**)&d_strains, m * n * 3 * sizeof(float)); CUDA_CHECK_ERRORS(); float* d_works; cudaMalloc((void**)&d_works, m * sizeof(float)); CUDA_CHECK_ERRORS(); float* d_partial_sums; int grid_size = (m + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; cudaMalloc((void**)&d_partial_sums, grid_size * sizeof(float)); CUDA_CHECK_ERRORS(); cudaMemset(d_partial_sums, 0, grid_size * sizeof(float)); CUDA_CHECK_ERRORS(); float* d_total_sum; cudaMalloc((void**)&d_total_sum, sizeof(float)); CUDA_CHECK_ERRORS(); cudaMemset(d_total_sum, 0, sizeof(float)); CUDA_CHECK_ERRORS(); // 数据复制到设备端 cudaMemcpy(d_strains, h_strains, m * n * 3 * sizeof(float), cudaMemcpyHostToDevice); CUDA_CHECK_ERRORS(); // 计算每个晶体的最大功,并求和 int block_size = THREADS_PER_BLOCK; int grid_size_calc = grid_size; calculate_max_work_and_sum<<<grid_size_calc, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums); CUDA_CHECK_ERRORS(); // 对 partial_sums 进行求和 int grid_size_sum = (grid_size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; sum_partial_sums<<<grid_size_sum, block_size>>>(d_partial_sums, grid_size, d_total_sum); CUDA_CHECK_ERRORS(); // 复制 total_sum 回主机端 float total_work; cudaMemcpy(&total_work, d_total_sum, sizeof(float), cudaMemcpyDeviceToHost); CUDA_CHECK_ERRORS(); // 计算平均功 float average_work = total_work / m; // 输出结果 std::cout << "Average work: " << std::setprecision(6) << average_work << std::endl; // 释放内存 delete[] h_strains; cudaFree(d_strains); cudaFree(d_works); cudaFree(d_partial_sums); cudaFree(d_total_sum); return 0; } // 核心函数定义 __global__ void calculate_max_work_and_sum(float* strains, float* works, float* stress, int m, int n, float* partial_sums) { __shared__ float shared_sums[THREADS_PER_BLOCK]; int crystal = blockIdx.x * blockDim.x + threadIdx.x; float max_work = -INFINITY; if (crystal < m) { for (int variant = 0; variant < n; variant++) { float strain_x = strains[crystal * n * 3 + variant * 3 + 0]; float strain_y = strains[crystal * n * 3 + variant * 3 + 1]; float strain_z = strains[crystal * n * 3 + variant * 3 + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(partial_sums + blockIdx.x, shared_sums[0]); } } __global__ void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum) { __shared__ float shared_sums[THREADS_PER_BLOCK]; int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < grid_size) { shared_sums[threadIdx.x] = partial_sums[idx]; } else { shared_sums[threadIdx.x] = 0.0f; } __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(total_sum, shared_sums[0]); } }
引用要利用GPU并行计算多晶体中每个晶体的功并求其平均值,可以按照以下步骤进行实现:
  1. 数据准备与存储:
    • 每个晶体有 nn 个可能的马氏体变体,每个变体有一个应变向量。将所有晶体的应变数据存储在一个一维数组 strains 中,大小为 m \times n \times 3m×n×3,其中 mm 是晶体数量。
    • 应力向量为单位向量,存储在数组 stress 中。
  2. GPU内存分配与初始化:
    • 在设备端分配内存用于存储应变数据 d_strains、每个晶体的最大功 d_works、部分和 d_partial_sums 以及总和 d_total_sum。
    • 将主机端的应变数据复制到设备端。
  3. 并行计算核函数:
    • 编写核函数 calculate_max_work_and_sum,每个线程负责一个晶体,计算该晶体所有变体的功,取最大值存储在 d_works 中,并将最大功加到对应的部分和 d_partial_sums 中。
    • 使用共享内存进行块内减少,以提高求和效率。
  4. 部分和的汇总:
    • 编写核函数 sum_partial_sums,对 d_partial_sums 中的partial sums进行进一步求和,得到总的功 total_work。
  5. 结果回传与计算平均功:
    • 将总功 total_work 从设备端回传到主机端,计算平均功 average_work。
  6. 内存释放:
    • 释放设备端和主机端分配的内存。
以下是完整的GPU实现代码:
cpp
复制
#include <cuda_runtime.h> #include <device_launch_parameters.h> #include <iostream> #include <iomanip> #include <cmath> #define THREADS_PER_BLOCK 256 // 错误检查宏 #define CUDA_CHECK_ERRORS() { \ cudaError_t e = cudaGetLastError(); \ if(e != cudaSuccess) { \ printf("CUDA error: %s\n", cudaGetErrorString(e)); \ cudaFree(d_strains); \ cudaFree(d_works); \ cudaFree(d_partial_sums); \ cudaFree(d_total_sum); \ delete[] h_strains; \ exit(1); \ } \ } // 核心函数声明 __global__ void calculate_max_work_and_sum(float* strains, float* works, const float* stress, int m, int n, float* partial_sums); __global__ void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum); int main() { int m = 1000000; // 晶体数 int n = 10; // 变体数 float stress[3] = {1.0f, 0.0f, 0.0f}; // 单位应力向量 // 生成应变数据 float* h_strains = new float[m * n * 3]; for (int i = 0; i < m * n * 3; i++) { h_strains[i] = drand48(); // 随机应变数据 } // 设备端内存分配 float* d_strains; cudaMalloc((void**)&d_strains, m * n * 3 * sizeof(float)); CUDA_CHECK_ERRORS(); float* d_works; cudaMalloc((void**)&d_works, m * sizeof(float)); CUDA_CHECK_ERRORS(); int grid_size = (m + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; float* d_partial_sums; cudaMalloc((void**)&d_partial_sums, grid_size * sizeof(float)); CUDA_CHECK_ERRORS(); cudaMemset(d_partial_sums, 0, grid_size * sizeof(float)); CUDA_CHECK_ERRORS(); float* d_total_sum; cudaMalloc((void**)&d_total_sum, sizeof(float)); CUDA_CHECK_ERRORS(); cudaMemset(d_total_sum, 0, sizeof(float)); CUDA_CHECK_ERRORS(); // 数据复制到设备端 cudaMemcpy(d_strains, h_strains, m * n * 3 * sizeof(float), cudaMemcpyHostToDevice); CUDA_CHECK_ERRORS(); // 计算每个晶体的最大功,并求和 int block_size = THREADS_PER_BLOCK; calculate_max_work_and_sum<<<grid_size, block_size>>>(d_strains, d_works, stress, m, n, d_partial_sums); CUDA_CHECK_ERRORS(); // 对 partial_sums 进行求和 int grid_size_sum = (grid_size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; sum_partial_sums<<<grid_size_sum, block_size>>>(d_partial_sums, grid_size, d_total_sum); CUDA_CHECK_ERRORS(); // 复制 total_sum 回主机端 float total_work; cudaMemcpy(&total_work, d_total_sum, sizeof(float), cudaMemcpyDeviceToHost); CUDA_CHECK_ERRORS(); // 计算平均功 float average_work = total_work / m; // 输出结果 std::cout << "Average work: " << std::setprecision(6) << average_work << std::endl; // 释放内存 delete[] h_strains; cudaFree(d_strains); cudaFree(d_works); cudaFree(d_partial_sums); cudaFree(d_total_sum); return 0; } // 核心函数定义 __global__ void calculate_max_work_and_sum(float* strains, float* works, const float* stress, int m, int n, float* partial_sums) { __shared__ float shared_sums[THREADS_PER_BLOCK]; int crystal = blockIdx.x * blockDim.x + threadIdx.x; float max_work = -INFINITY; if (crystal < m) { for (int variant = 0; variant < n; variant++) { int index = crystal * n * 3 + variant * 3; float strain_x = strains[index + 0]; float strain_y = strains[index + 1]; float strain_z = strains[index + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(partial_sums + blockIdx.x, shared_sums[0]); } } __global__ void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum) { __shared__ float shared_sums[THREADS_PER_BLOCK]; int idx = blockIdx.x * blockDim.x + threadIdx.x; shared_sums[threadIdx.x] = (idx < grid_size) ? partial_sums[idx] : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(total_sum, shared_sums[0]); } }
​用户_DymLdr
用上诉方式求出各种应力状态下对应的平均值,再除以单向拉伸的平均值,就可以得出normalized的屈服面
Zero推理模型
引用要计算归一化的屈服面,你需要在不同应力状态下计算平均功,然后将这些平均功除以单向拉伸条件下的平均功。这将给你一个归一化的值,表示在不同应力状态下晶体的屈服行为相对于单向拉伸的屈服行为。
以下是一个示例代码,展示了如何计算归一化的屈服面:
cpp
复制
#include <iostream> #include <vector> #include <cmath> #include <cuda_runtime.h> // 定义常量 const int THREADS_PER_BLOCK = 256; // CUDA错误检查宏 #define CUDA_CHECK_ERRORS() { cudaError_t err = cudaGetLastError(); if (err != cudaSuccess) { std::cerr << "CUDA error: " << cudaGetErrorString(err) << std::endl; exit(1); } } // 核心函数声明 __global__ void calculate_max_work_and_sum(float* strains, float* works, const float* stress, int m, int n, float* partial_sums); __global__ void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum); int main() { // 参数设置 int m = 1000; // 晶体数量 int n = 100; // 变体数量 int num_stress_states = 10; // 不同应力状态的数量 // 生成随机应变数据 std::vector<float> h_strains(m * n * 3); for (int i = 0; i < m * n * 3; i++) { h_strains[i] = static_cast<float>(rand()) / RAND_MAX; // 随机应变值 } // 定义应力状态 std::vector<std::vector<float>> stress_states(num_stress_states, std::vector<float>(3)); for (int i = 0; i < num_stress_states; i++) { // 这里可以定义不同的应力状态,例如单向拉伸、剪切等 stress_states[i][0] = static_cast<float>(rand()) / RAND_MAX; // sigma_x stress_states[i][1] = static_cast<float>(rand()) / RAND_MAX; // sigma_y stress_states[i][2] = static_cast<float>(rand()) / RAND_MAX; // sigma_z } // 分配设备内存 float* d_strains; float* d_works; float* d_partial_sums; float* d_total_sum; cudaMalloc(&d_strains, m * n * 3 * sizeof(float)); cudaMalloc(&d_works, m * sizeof(float)); cudaMalloc(&d_partial_sums, m * sizeof(float)); cudaMalloc(&d_total_sum, sizeof(float)); CUDA_CHECK_ERRORS(); // 计算单向拉伸条件下的平均功 std::vector<float> average_works(num_stress_states); for (int s = 0; s < num_stress_states; s++) { // 复制应变数据到设备 cudaMemcpy(d_strains, h_strains.data(), m * n * 3 * sizeof(float), cudaMemcpyHostToDevice); CUDA_CHECK_ERRORS(); // 设置应力状态 const float* stress = stress_states[s].data(); // 计算每个晶体的最大功,并求和 int grid_size = (m + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; calculate_max_work_and_sum<<<grid_size, THREADS_PER_BLOCK>>>(d_strains, d_works, stress, m, n, d_partial_sums); CUDA_CHECK_ERRORS(); // 对 partial_sums 进行求和 int grid_size_sum = (grid_size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; sum_partial_sums<<<grid_size_sum, THREADS_PER_BLOCK>>>(d_partial_sums, grid_size, d_total_sum); CUDA_CHECK_ERRORS(); // 复制 total_sum 回主机端 float total_work; cudaMemcpy(&total_work, d_total_sum, sizeof(float), cudaMemcpyDeviceToHost); CUDA_CHECK_ERRORS(); // 计算平均功 average_works[s] = total_work / m; } // 计算单向拉伸条件下的平均功(假设第一个应力状态是单向拉伸) float average_work_uniaxial = average_works[0]; // 计算归一化的屈服面 std::vector<float> normalized_yields(num_stress_states); for (int s = 0; s < num_stress_states; s++) { normalized_yields[s] = average_works[s] / average_work_uniaxial; } // 输出结果 for (int s = 0; s < num_stress_states; s++) { std::cout << "Stress State " << s << " Normalized Yield: " << std::setprecision(6) << normalized_yields[s] << std::endl; } // 释放内存 cudaFree(d_strains); cudaFree(d_works); cudaFree(d_partial_sums); cudaFree(d_total_sum); return 0; } // 核心函数定义 __global__ void calculate_max_work_and_sum(float* strains, float* works, const float* stress, int m, int n, float* partial_sums) { __shared__ float shared_sums[THREADS_PER_BLOCK]; int crystal = blockIdx.x * blockDim.x + threadIdx.x; float max_work = -INFINITY; if (crystal < m) { for (int variant = 0; variant < n; variant++) { int index = crystal * n * 3 + variant * 3; float strain_x = strains[index + 0]; float strain_y = strains[index + 1]; float strain_z = strains[index + 2]; float work = stress[0] * strain_x + stress[1] * strain_y + stress[2] * strain_z; if (work > max_work) { max_work = work; } } works[crystal] = max_work; } shared_sums[threadIdx.x] = (crystal < m) ? max_work : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(partial_sums + blockIdx.x, shared_sums[0]); } } __global__ void sum_partial_sums(float* partial_sums, int grid_size, float* total_sum) { __shared__ float shared_sums[THREADS_PER_BLOCK]; int idx = blockIdx.x * blockDim.x + threadIdx.x; shared_sums[threadIdx.x] = (idx < grid_size) ? partial_sums[idx] : 0.0f; __syncthreads(); // 减少求和 for (int s = blockDim.x / 2; s > 0; s >>= 1) { if (threadIdx.x < s) { shared_sums[threadIdx.x] += shared_sums[threadIdx.x + s]; } __syncthreads(); } if (threadIdx.x == 0) { atomicAdd(total_sum, shared_sums[0]); } } 在这个示例中,我们首先生成了一组随机的应变数据,然后定义了多个不同的应力状态。对于每个应力状态,我们计算了晶体的最大功并求和,最终得到了每个应力状态下的平均功。然后,我们将这些平均功除以单向拉伸条件下的平均功,得到了归一化的屈服面。
请注意,这只是一个示例代码,实际应用中你可能需要根据具体情况调整应力状态的定义和应变数据的生成方式。此外,你可能还需要考虑应力状态的物理意义和晶体的微观结构等因素。

​Mathematical equation of unified fracture criterion
Powered by Create your own unique website with customizable templates.
  • HOME
  • SHAPE MEMORY MATERIALS/TECHNOLOGY
    • Shape memory alloys >
      • Shape memory alloy actuators
      • Grains and deformation
      • SMA suppliers
    • Shape memory polymers >
      • Thermo-responsive >
        • Heating-responsive >
          • Thermo-plastic elastic SMP >
            • Body/room temperature programmable
          • Thermoset elastic SMP >
            • Body/room temperature programmable
          • Tailoring Tg of polymers via alloying
          • Vitrimer
          • 3D printing filaments
          • Show time
          • Body-temperature programmable elastic shape memory materials: a brief history
        • Cooling-responsive >
          • Cooling-responsive shape memory materials: a brief history
      • Chemo-responsive >
        • Electrospinning: fundametals
        • Natural biopolymers
        • Water-responsive SME: a brief history
      • Hydrogel
      • Simulation of SMP
    • Shape memory hybrids >
      • Electro-activated shape memory hybrid
      • SMHs: tailorable properties
      • Shape memory hybrids: a brief history
    • Triple/multiple SME
    • Reversible/shape change effect
    • Programming conditions
    • Temperature memory effect in DSC
    • Buckling 失稳
    • Constrained recovery of 2way EVA
    • Shape memory structures
    • Shape memory composites
    • Intro. & Refs. >
      • SME in commercial polymers
      • SMM introduction videos
      • PMMA (acrylic)
  • DIY
    • Laser engraving and beyond
    • DIY (step-by-step) to protect power charge cable 自制充电线接头保护层
    • DIY SMP screw 自制形状记忆螺丝
    • DIY shape memory foam 自制形状记忆海绵
    • DIY shape memory shoes 自制形状记忆鞋
    • Modifying superelastic Nitinol 超弹镍钛记忆合金改性
    • Goggles
    • Temple Tip Retainers /眼镜防滑钩
    • Nose pads
    • 硅胶+TPU样品制作 搅拌流程
    • Unlock smart phones
  • PROJECTS
    • Biomedical applications 生物医疗应用 >
      • Self-tightening band aid 自收缩创可贴
      • Self-tightening staple 自收缩手术钉
      • Shape memory plug 形状记忆栓塞
      • Artificial blood vessels
      • Comfort fitting 舒适贴合 >
        • Shape memory shoes 形状记忆鞋
        • Wrist rings/rings
        • Mask口罩 >
          • DIY口罩扣松紧器
          • Mask holder 口罩支架
          • Improved fitting
          • Comfort fitting "invisible" mask 舒适贴合“隐形”口罩 >
            • Animation (mask)
        • Facial mask (面膜)
      • Retractable 可收回
      • Wrinkle removal 除皱
    • SMA devices 形状记忆合金器件 >
      • Buttons-on-demand 按需按钮
      • Sunlight activated heat engine 阳光驱动的热机
      • Adjustable high heel 可调高跟鞋
      • SMA inchworm 形状记忆合金驱动的竹节虫
      • Rolling car 滚动车
      • SMA springs
      • Gripper
    • SMP applications >
      • 4D latte art 4D 拉花 >
        • Spinning 4D latte art
      • Re-writable Braille paper 可复写盲文纸
      • Surface patterning
      • 2D to 3D switching
      • Ear impression/plugs
    • Metals/polymers >
      • Smart manufacturing
      • Powerless cooling
      • Self-healing
      • Sensors 传感器 >
        • Temperature sensors 温度标签
        • Anti-counterfeit labels 防伪标签
      • Vertical gardening 垂直绿化 >
        • 盆景 >
          • In Singapore
        • Products 产品 >
          • Event sponsorship
        • Projects 项目 >
          • A project in Guangzhou (2022)
          • 2nd Project in Guangzhou
          • 3rd Project in Singapore
        • Water on-demand irrigation system
        • Vertical greening panel (2nd type)
        • 2nd type of foam
      • Wearable electronics 可穿戴电子设备
      • Controlled folding/unfolding 可控展开/折叠 >
        • Folding (multiple layered)
        • Reshape & reprogram
      • Active disassembly 自拆卸
      • Morphing wing 变翼
      • Magnetic circuit design
    • Solid state UV cross-linking >
      • Solid-state heating cross-linking
    • Additive manufacturing增材制造 >
      • 3D/4D printing 打印
      • Rapid 3D printing in solid state 快速固态3D打印 >
        • Rapid volumetric additive manufacturing in solid-state: hydrogels
        • UV cross-linkable vitrimer 2022
        • UV cross-linking of solid material
        • UV cross-linking machine
        • Solid-state VAM (3D)
        • SVAM: A brief history
        • Review of Solid state VAM by AI
      • New ways of additive manufacturing (animation)
      • UV-FDM printer
      • Cooling-responsive shape memory hydrogel via FDM
      • 3D fashion >
        • Formation of 3D structures
    • Shape capture
    • Surface capture >
      • Surface pattern for structural coloring
  • Store room
    • References/tools >
      • 3D models >
        • More STL models
        • 生肖
        • 3D printing service
      • Sample dimensions for tensile test
      • Temperature calibration
      • Toolbox工具箱
      • Toolbox II (工具箱 II)
    • Jungle >
      • About polymers >
        • Thermally reversible solid-liquid transition
        • Cyclic loading
        • Mullins effect
        • Photoelsticity 光弹
        • Shear-thickening 剪切增强 >
          • 4 CNA
        • Closed to open cell foams
        • Laser induced graphene
        • Electrospinning
        • Nano imprinting
        • Gel 凝胶 >
          • Instability in wetting of hydrogel
          • Electroactive gel电活性凝胶
        • Cellulose 纤维素
        • Plastic bottle 塑料瓶
        • Polymer recycling
        • Rapid swelling 快速溶胀
        • Rapid hardening in water
        • Patterns
        • Brittle-ductile transition
        • Tan delta >
          • Re-programmable Tan delta
        • UV cross-linking
        • Hardening speed
      • Coloring 变色 >
        • Structural coloring atop curved surfaces
        • Thermochromic 热致变色
        • Photochromic 光致变色
        • Stress induced color change力致变色 >
          • Patterned coloring via stretching 拉出色彩
      • Moire interference 莫尔干涉
      • Lenticular lens
      • Transformation front
      • Contact angle vs surface pattern
      • Laser: applications
      • Insects 昆虫
      • Structural engineer >
        • Static and Dynamic Balancing
        • Introduction videos
        • Bistable structures: a case study >
          • 3D printing of bistable structures
          • Step-wise morphing
        • Yield criterion >
          • Normalized yield surface via GPU
          • Yield surface of SMAs and beyond
        • Buckling of embedded threads
        • Buckling of embedded strip
        • Buckling of strip atop soft substrate
        • Foam structures for packaging
      • Interesting >
        • Exhibition
        • Ideas
      • Experimental >
        • Tensile test
        • Differential Scanning Calorimetry (DSC) Procedure
        • Dynamic Mechanical Analysis (DMA) Procedure
        • Shape Memory Performance Characterization Procedure for Shape Memory Polymers
      • ChatGPT 4 fun
      • 智谱测试
  • Contact
    • SMM course
    • Representative publications
    • Projects of undergraduate students
    • List of videos
    • Special issues| Conferences
    • Companies
    • References